home *** CD-ROM | disk | FTP | other *** search
/ Aminet 48 / Aminet 48 (2002)(GTI - Schatztruhe)[!][Apr 2002].iso / Aminet / text / edit / vim60src.lha / Vim / vim60 / src / memline.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-09-09  |  115.2 KB  |  4,364 lines

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved    by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  * See README.txt for an overview of the Vim source code.
  8.  */
  9.  
  10. /* for debugging */
  11. /* #define CHECK(c, s)    if (c) EMSG(s) */
  12. #define CHECK(c, s)
  13.  
  14. /*
  15.  * memline.c: Contains the functions for appending, deleting and changing the
  16.  * text lines. The memfile functions are used to store the information in blocks
  17.  * of memory, backed up by a file. The structure of the information is a tree.
  18.  * The root of the tree is a pointer block. The leaves of the tree are data
  19.  * blocks. In between may be several layers of pointer blocks, forming branches.
  20.  *
  21.  * Three types of blocks are used:
  22.  * - Block nr 0 contains information for recovery
  23.  * - Pointer blocks contain list of pointers to other blocks.
  24.  * - Data blocks contain the actual text.
  25.  *
  26.  * Block nr 0 contains the block0 structure (see below).
  27.  *
  28.  * Block nr 1 is the first pointer block. It is the root of the tree.
  29.  * Other pointer blocks are branches.
  30.  *
  31.  *  If a line is too big to fit in a single page, the block containing that
  32.  *  line is made big enough to hold the line. It may span several pages.
  33.  *  Otherwise all blocks are one page.
  34.  *
  35.  *  A data block that was filled when starting to edit a file and was not
  36.  *  changed since then, can have a negative block number. This means that it
  37.  *  has not yet been assigned a place in the file. When recovering, the lines
  38.  *  in this data block can be read from the original file. When the block is
  39.  *  changed (lines appended/deleted/changed) or when it is flushed it gets a
  40.  *  positive number. Use mf_trans_del() to get the new number, before calling
  41.  *  mf_get().
  42.  */
  43.  
  44. #if defined(MSDOS) || defined(WIN32) || defined(_WIN64)
  45. # include <io.h>
  46. #endif
  47.  
  48. #include "vim.h"
  49.  
  50. #ifdef HAVE_FCNTL_H
  51. # include <fcntl.h>
  52. #endif
  53. #ifndef UNIX        /* it's in os_unix.h for Unix */
  54. # include <time.h>
  55. #endif
  56.  
  57. #ifdef SASC
  58. # include <proto/dos.h>        /* for Open() and Close() */
  59. #endif
  60.  
  61. typedef struct block0        ZERO_BL;    /* contents of the first block */
  62. typedef struct pointer_block    PTR_BL;        /* contents of a pointer block */
  63. typedef struct data_block    DATA_BL;    /* contents of a data block */
  64. typedef struct pointer_entry    PTR_EN;        /* block/line-count pair */
  65.  
  66. #define DATA_ID        (('d' << 8) + 'a')        /* data block id */
  67. #define PTR_ID        (('p' << 8) + 't')        /* pointer block id */
  68. #define BLOCK0_ID0  'b'                /* block 0 id 0 */
  69. #define BLOCK0_ID1  '0'                /* block 0 id 1 */
  70.  
  71. /*
  72.  * pointer to a block, used in a pointer block
  73.  */
  74. struct pointer_entry
  75. {
  76.     blocknr_T    pe_bnum;    /* block number */
  77.     linenr_T    pe_line_count;    /* number of lines in this branch */
  78.     linenr_T    pe_old_lnum;    /* lnum for this block (for recovery) */
  79.     int        pe_page_count;    /* number of pages in block pe_bnum */
  80. };
  81.  
  82. /*
  83.  * A pointer block contains a list of branches in the tree.
  84.  */
  85. struct pointer_block
  86. {
  87.     short_u    pb_id;        /* ID for pointer block: PTR_ID */
  88.     short_u    pb_count;    /* number of pointer in this block */
  89.     short_u    pb_count_max;    /* maximum value for pb_count */
  90.     PTR_EN    pb_pointer[1];    /* list of pointers to blocks (actually longer)
  91.                  * followed by empty space until end of page */
  92. };
  93.  
  94. /*
  95.  * A data block is a leaf in the tree.
  96.  *
  97.  * The text of the lines is at the end of the block. The text of the first line
  98.  * in the block is put at the end, the text of the second line in front of it,
  99.  * etc. Thus the order of the lines is the opposite of the line number.
  100.  */
  101. struct data_block
  102. {
  103.     short_u    db_id;        /* ID for data block: DATA_ID */
  104.     unsigned    db_free;    /* free space available */
  105.     unsigned    db_txt_start;    /* byte where text starts */
  106.     unsigned    db_txt_end;    /* byte just after data block */
  107.     linenr_T    db_line_count;    /* number of lines in this block */
  108.     unsigned    db_index[1];    /* index for start of line (actually bigger)
  109.                  * followed by empty space upto db_txt_start
  110.                  * followed by the text in the lines until
  111.                  * end of page */
  112. };
  113.  
  114. /*
  115.  * The low bits of db_index hold the actual index. The topmost bit is
  116.  * used for the global command to be able to mark a line.
  117.  * This method is not clean, but otherwise there would be at least one extra
  118.  * byte used for each line.
  119.  * The mark has to be in this place to keep it with the correct line when other
  120.  * lines are inserted or deleted.
  121.  */
  122. #define DB_MARKED    ((unsigned)1 << ((sizeof(unsigned) * 8) - 1))
  123. #define DB_INDEX_MASK    (~DB_MARKED)
  124.  
  125. #define INDEX_SIZE  (sizeof(unsigned))        /* size of one db_index entry */
  126. #define HEADER_SIZE (sizeof(DATA_BL) - INDEX_SIZE)  /* size of data block header */
  127.  
  128. #define B0_FNAME_SIZE    900
  129. #define B0_UNAME_SIZE    40
  130. #define B0_HNAME_SIZE    40
  131. /*
  132.  * Restrict the numbers to 32 bits, otherwise most compilers will complain.
  133.  * This won't detect a 64 bit machine that only swaps a byte in the top 32
  134.  * bits, but that is crazy anyway.
  135.  */
  136. #define B0_MAGIC_LONG    0x30313233L
  137. #define B0_MAGIC_INT    0x20212223L
  138. #define B0_MAGIC_SHORT    0x10111213L
  139. #define B0_MAGIC_CHAR    0x55
  140.  
  141. /*
  142.  * Block zero holds all info about the swap file.
  143.  *
  144.  * NOTE: DEFINITION OF BLOCK 0 SHOULD NOT CHANGE! It would make all existing
  145.  * swap files unusable!
  146.  *
  147.  * If size of block0 changes anyway, adjust MIN_SWAP_PAGE_SIZE in vim.h!!
  148.  *
  149.  * This block is built up of single bytes, to make it portable accros
  150.  * different machines. b0_magic_* is used to check the byte order and size of
  151.  * variables, because the rest of the swap file is not portable.
  152.  */
  153. struct block0
  154. {
  155.     char_u    b0_id[2];    /* id for block 0: BLOCK0_ID0 and BLOCK0_ID1 */
  156.     char_u    b0_version[10];    /* Vim version string */
  157.     char_u    b0_page_size[4];/* number of bytes per page */
  158.     char_u    b0_mtime[4];    /* last modification time of file */
  159.     char_u    b0_ino[4];    /* inode of b0_fname */
  160.     char_u    b0_pid[4];    /* process id of creator (or 0) */
  161.     char_u    b0_uname[B0_UNAME_SIZE]; /* name of user (uid if no name) */
  162.     char_u    b0_hname[B0_HNAME_SIZE]; /* host name (if it has a name) */
  163.     char_u    b0_fname[B0_FNAME_SIZE]; /* name of file being edited */
  164.     long    b0_magic_long;    /* check for byte order of long */
  165.     int        b0_magic_int;    /* check for byte order of int */
  166.     short    b0_magic_short;    /* check for byte order of short */
  167.     char_u    b0_magic_char;    /* check for last char */
  168. };
  169. #define   b0_dirty b0_fname[B0_FNAME_SIZE-1]
  170.  
  171. #define STACK_INCR    5    /* nr of entries added to ml_stack at a time */
  172.  
  173. /*
  174.  * The line number where the first mark may be is remembered.
  175.  * If it is 0 there are no marks at all.
  176.  * (always used for the current buffer only, no buffer change possible while
  177.  * executing a global command).
  178.  */
  179. static linenr_T    lowest_marked = 0;
  180.  
  181. /*
  182.  * arguments for ml_find_line()
  183.  */
  184. #define ML_DELETE    0x11        /* delete line */
  185. #define ML_INSERT    0x12        /* insert line */
  186. #define ML_FIND        0x13        /* just find the line */
  187. #define ML_FLUSH    0x02        /* flush locked block */
  188. #define ML_SIMPLE(x)    (x & 0x10)  /* DEL, INS or FIND */
  189.  
  190. static void set_b0_fname __ARGS((ZERO_BL *, buf_T *buf));
  191. static time_t swapfile_info __ARGS((char_u *));
  192. static int recov_file_names __ARGS((char_u **, char_u *, int prepend_dot));
  193. static int ml_append_int __ARGS((buf_T *, linenr_T, char_u *, colnr_T, int, int));
  194. static int ml_delete_int __ARGS((buf_T *, linenr_T, int));
  195. static char_u *findswapname __ARGS((buf_T *, char_u **, char_u *));
  196. static void ml_flush_line __ARGS((buf_T *));
  197. static bhdr_T *ml_new_data __ARGS((memfile_T *, int, int));
  198. static bhdr_T *ml_new_ptr __ARGS((memfile_T *));
  199. static bhdr_T *ml_find_line __ARGS((buf_T *, linenr_T, int));
  200. static int ml_add_stack __ARGS((buf_T *));
  201. static char_u *makeswapname __ARGS((buf_T *, char_u *));
  202. static void ml_lineadd __ARGS((buf_T *, int));
  203. static int b0_magic_wrong __ARGS((ZERO_BL *));
  204. #ifdef CHECK_INODE
  205. static int fnamecmp_ino __ARGS((char_u *, char_u *, long));
  206. #endif
  207. static void long_to_char __ARGS((long, char_u *));
  208. static long char_to_long __ARGS((char_u *));
  209. #if defined(UNIX) || defined(WIN3264)
  210. static char_u *make_percent_swname __ARGS((char_u *dir, char_u *name));
  211. #endif
  212. #ifdef FEAT_BYTEOFF
  213. static void ml_updatechunk __ARGS((buf_T *buf, long line, int len, int updtype));
  214. #endif
  215.  
  216. /*
  217.  * open a new memline for 'curbuf'
  218.  *
  219.  * return FAIL for failure, OK otherwise
  220.  */
  221.     int
  222. ml_open()
  223. {
  224.     memfile_T    *mfp;
  225.     bhdr_T    *hp = NULL;
  226.     ZERO_BL    *b0p;
  227.     PTR_BL    *pp;
  228.     DATA_BL    *dp;
  229.  
  230. /*
  231.  * init fields in memline struct
  232.  */
  233.     curbuf->b_ml.ml_stack_size = 0;    /* no stack yet */
  234.     curbuf->b_ml.ml_stack = NULL;    /* no stack yet */
  235.     curbuf->b_ml.ml_stack_top = 0;    /* nothing in the stack */
  236.     curbuf->b_ml.ml_locked = NULL;    /* no cached block */
  237.     curbuf->b_ml.ml_line_lnum = 0;    /* no cached line */
  238. #ifdef FEAT_BYTEOFF
  239.     curbuf->b_ml.ml_chunksize = NULL;
  240. #endif
  241.  
  242. /*
  243.  * When 'updatecount' is non-zero, flag that a swap file may be opened later.
  244.  */
  245.     if (p_uc && curbuf->b_p_swf)
  246.     curbuf->b_may_swap = TRUE;
  247.     else
  248.     curbuf->b_may_swap = FALSE;
  249.  
  250. /*
  251.  * Open the memfile.  No swap file is created yet.
  252.  */
  253.     mfp = mf_open(NULL, 0);
  254.     if (mfp == NULL)
  255.     goto error;
  256.  
  257.     curbuf->b_ml.ml_mfp = mfp;
  258.     curbuf->b_ml.ml_flags = ML_EMPTY;
  259.     curbuf->b_ml.ml_line_count = 1;
  260.  
  261. #if defined(MSDOS) && !defined(DJGPP)
  262.     /* for 16 bit MS-DOS create a swapfile now, because we run out of
  263.      * memory very quickly */
  264.     if (p_uc != 0)
  265.     ml_open_file(curbuf);
  266. #endif
  267.  
  268. /*
  269.  * fill block0 struct and write page 0
  270.  */
  271.     if ((hp = mf_new(mfp, FALSE, 1)) == NULL)
  272.     goto error;
  273.     if (hp->bh_bnum != 0)
  274.     {
  275.     EMSG(_("E298: Didn't get block nr 0?"));
  276.     goto error;
  277.     }
  278.     b0p = (ZERO_BL *)(hp->bh_data);
  279.  
  280.     b0p->b0_id[0] = BLOCK0_ID0;
  281.     b0p->b0_id[1] = BLOCK0_ID1;
  282.     b0p->b0_dirty = curbuf->b_changed ? 0x55 : 0;
  283.     b0p->b0_magic_long = (long)B0_MAGIC_LONG;
  284.     b0p->b0_magic_int = (int)B0_MAGIC_INT;
  285.     b0p->b0_magic_short = (short)B0_MAGIC_SHORT;
  286.     b0p->b0_magic_char = B0_MAGIC_CHAR;
  287.  
  288.     STRNCPY(b0p->b0_version, "VIM ", 4);
  289.     STRNCPY(b0p->b0_version + 4, Version, 6);
  290.     set_b0_fname(b0p, curbuf);
  291.     long_to_char((long)mfp->mf_page_size, b0p->b0_page_size);
  292.     (void)get_user_name(b0p->b0_uname, B0_UNAME_SIZE);
  293.     b0p->b0_uname[B0_UNAME_SIZE - 1] = NUL;
  294.     mch_get_host_name(b0p->b0_hname, B0_HNAME_SIZE);
  295.     b0p->b0_hname[B0_HNAME_SIZE - 1] = NUL;
  296.     long_to_char(mch_get_pid(), b0p->b0_pid);
  297.  
  298.     /*
  299.      * Always sync block number 0 to disk, so we can check the file name in
  300.      * the swap file in findswapname(). Don't do this for help files though.
  301.      * Only works when there's a swapfile, otherwise it's done when the file
  302.      * is created.
  303.      */
  304.     mf_put(mfp, hp, TRUE, FALSE);
  305.     if (!curbuf->b_help)
  306.     (void)mf_sync(mfp, 0);
  307.  
  308. /*
  309.  * fill in root pointer block and write page 1
  310.  */
  311.     if ((hp = ml_new_ptr(mfp)) == NULL)
  312.     goto error;
  313.     if (hp->bh_bnum != 1)
  314.     {
  315.     EMSG(_("E298: Didn't get block nr 1?"));
  316.     goto error;
  317.     }
  318.     pp = (PTR_BL *)(hp->bh_data);
  319.     pp->pb_count = 1;
  320.     pp->pb_pointer[0].pe_bnum = 2;
  321.     pp->pb_pointer[0].pe_page_count = 1;
  322.     pp->pb_pointer[0].pe_old_lnum = 1;
  323.     pp->pb_pointer[0].pe_line_count = 1;    /* line count after insertion */
  324.     mf_put(mfp, hp, TRUE, FALSE);
  325.  
  326. /*
  327.  * allocate first data block and create an empty line 1.
  328.  */
  329.     if ((hp = ml_new_data(mfp, FALSE, 1)) == NULL)
  330.     goto error;
  331.     if (hp->bh_bnum != 2)
  332.     {
  333.     EMSG(_("E298: Didn't get block nr 2?"));
  334.     goto error;
  335.     }
  336.  
  337.     dp = (DATA_BL *)(hp->bh_data);
  338.     dp->db_index[0] = --dp->db_txt_start;    /* at end of block */
  339.     dp->db_free -= 1 + INDEX_SIZE;
  340.     dp->db_line_count = 1;
  341.     *((char_u *)dp + dp->db_txt_start) = NUL;    /* emtpy line */
  342.  
  343.     return OK;
  344.  
  345. error:
  346.     if (mfp != NULL)
  347.     {
  348.     if (hp)
  349.         mf_put(mfp, hp, FALSE, FALSE);
  350.     mf_close(mfp, TRUE);        /* will also free(mfp->mf_fname) */
  351.     }
  352.     curbuf->b_ml.ml_mfp = NULL;
  353.     return FAIL;
  354. }
  355.  
  356. /*
  357.  * ml_setname() is called when the file name has been changed.
  358.  * It may rename the swap file.
  359.  */
  360.     void
  361. ml_setname()
  362. {
  363.     int        success = FALSE;
  364.     memfile_T    *mfp;
  365.     char_u    *fname;
  366.     char_u    *dirp;
  367. #if defined(MSDOS) || defined(MSWIN)
  368.     char_u    *p;
  369. #endif
  370.  
  371.     mfp = curbuf->b_ml.ml_mfp;
  372.     if (mfp->mf_fd < 0)            /* there is no swap file yet */
  373.     {
  374.     /*
  375.      * When 'updatecount' is 0 and 'noswapfile' there is no swap file.
  376.      * For help files we will make a swap file now.
  377.      */
  378.     if (p_uc != 0)
  379.         ml_open_file(curbuf);    /* create a swap file */
  380.     return;
  381.     }
  382.  
  383.     /*
  384.      * Try all directories in the 'directory' option.
  385.      */
  386.     dirp = p_dir;
  387.     for (;;)
  388.     {
  389.     if (*dirp == NUL)        /* tried all directories, fail */
  390.         break;
  391.     fname = findswapname(curbuf, &dirp, mfp->mf_fname); /* alloc's fname */
  392.     if (fname == NULL)        /* no file name found for this dir */
  393.         continue;
  394.  
  395. #if defined(MSDOS) || defined(MSWIN)
  396.     /*
  397.      * Set full pathname for swap file now, because a ":!cd dir" may
  398.      * change directory without us knowing it.
  399.      */
  400.     p = FullName_save(fname, FALSE);
  401.     vim_free(fname);
  402.     fname = p;
  403.     if (fname == NULL)
  404.         continue;
  405. #endif
  406.     /* if the file name is the same we don't have to do anything */
  407.     if (fnamecmp(fname, mfp->mf_fname) == 0)
  408.     {
  409.         vim_free(fname);
  410.         success = TRUE;
  411.         break;
  412.     }
  413.     /* need to close the swap file before renaming */
  414.     if (mfp->mf_fd >= 0)
  415.     {
  416.         close(mfp->mf_fd);
  417.         mfp->mf_fd = -1;
  418.     }
  419.  
  420.     /* try to rename the swap file */
  421.     if (vim_rename(mfp->mf_fname, fname) == 0)
  422.     {
  423.         success = TRUE;
  424.         vim_free(mfp->mf_fname);
  425.         mfp->mf_fname = fname;
  426.         vim_free(mfp->mf_ffname);
  427. #if defined(MSDOS) || defined(MSWIN)
  428.         mfp->mf_ffname = NULL;  /* mf_fname is full pathname already */
  429. #else
  430.         mf_set_ffname(mfp);
  431. #endif
  432.         break;
  433.     }
  434.     vim_free(fname);        /* this fname didn't work, try another */
  435.     }
  436.  
  437.     if (mfp->mf_fd == -1)        /* need to (re)open the swap file */
  438.     {
  439.     mfp->mf_fd = mch_open((char *)mfp->mf_fname, O_RDWR | O_EXTRA, 0);
  440.     if (mfp->mf_fd < 0)
  441.     {
  442.         /* could not (re)open the swap file, what can we do???? */
  443.         EMSG(_("E301: Oops, lost the swap file!!!"));
  444.         return;
  445.     }
  446.     }
  447.     if (!success)
  448.     EMSG(_("E302: Could not rename swap file"));
  449. }
  450.  
  451. /*
  452.  * Open a file for the memfile for all buffers that are not readonly or have
  453.  * been modified.
  454.  * Used when 'updatecount' changes from zero to non-zero.
  455.  */
  456.     void
  457. ml_open_files()
  458. {
  459.     buf_T    *buf;
  460.  
  461.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  462.     if (!buf->b_p_ro || buf->b_changed)
  463.         ml_open_file(buf);
  464. }
  465.  
  466. /*
  467.  * Open a swap file for an existing memfile, if there is no swap file yet.
  468.  * If we are unable to find a file name, mf_fname will be NULL
  469.  * and the memfile will be in memory only (no recovery possible).
  470.  */
  471.     void
  472. ml_open_file(buf)
  473.     buf_T    *buf;
  474. {
  475.     memfile_T    *mfp;
  476.     char_u    *fname;
  477.     char_u    *dirp;
  478.  
  479.     mfp = buf->b_ml.ml_mfp;
  480.     if (mfp == NULL || mfp->mf_fd >= 0 || !buf->b_p_swf)
  481.     return;        /* nothing to do */
  482.  
  483.     /*
  484.      * Try all directories in 'directory' option.
  485.      */
  486.     dirp = p_dir;
  487.     for (;;)
  488.     {
  489.     if (*dirp == NUL)
  490.         break;
  491.     /* There is a small chance that between chosing the swap file name and
  492.      * creating it, another Vim creates the file.  In that case the
  493.      * creation will fail and we will use another directory. */
  494.     fname = findswapname(buf, &dirp, NULL);    /* allocates fname */
  495.     if (fname == NULL)
  496.         continue;
  497.     if (mf_open_file(mfp, fname) == OK)    /* consumes fname! */
  498.     {
  499. #if defined(MSDOS) || defined(MSWIN) || defined(RISCOS)
  500.         /*
  501.          * set full pathname for swap file now, because a ":!cd dir" may
  502.          * change directory without us knowing it.
  503.          */
  504.         mf_fullname(mfp);
  505. #endif
  506.         /* Flush block zero, so others can read it */
  507.         if (mf_sync(mfp, MFS_ZERO) == OK)
  508.         break;
  509.         /* Writing block 0 failed: close the file and try another dir */
  510.         mf_close_file(buf, FALSE);
  511.     }
  512.     }
  513.  
  514.     if (mfp->mf_fname == NULL)        /* Failed! */
  515.     {
  516.     need_wait_return = TRUE;    /* call wait_return later */
  517.     ++no_wait_return;
  518.     (void)EMSG2(_("E303: Unable to open swap file for \"%s\", recovery impossible"),
  519.             buf_spname(buf) != NULL
  520.             ? (char_u *)buf_spname(buf)
  521.             : buf->b_fname);
  522.     --no_wait_return;
  523.     }
  524.  
  525.     /* don't try to open a swap file again */
  526.     buf->b_may_swap = FALSE;
  527. }
  528.  
  529. /*
  530.  * If still need to create a swap file, and starting to edit a not-readonly
  531.  * file, or reading into an existing buffer, create a swap file now.
  532.  */
  533.     void
  534. check_need_swap(newfile)
  535.     int        newfile;        /* reading file into new buffer */
  536. {
  537.     if (curbuf->b_may_swap && (!curbuf->b_p_ro || !newfile))
  538.     ml_open_file(curbuf);
  539. }
  540.  
  541. /*
  542.  * Close memline for buffer 'buf'.
  543.  * If 'del_file' is TRUE, delete the swap file
  544.  */
  545.     void
  546. ml_close(buf, del_file)
  547.     buf_T    *buf;
  548.     int        del_file;
  549. {
  550.     if (buf->b_ml.ml_mfp == NULL)        /* not open */
  551.     return;
  552.     mf_close(buf->b_ml.ml_mfp, del_file);    /* close the .swp file */
  553.     if (buf->b_ml.ml_line_lnum != 0 && (buf->b_ml.ml_flags & ML_LINE_DIRTY))
  554.     vim_free(buf->b_ml.ml_line_ptr);
  555.     vim_free(buf->b_ml.ml_stack);
  556. #ifdef FEAT_BYTEOFF
  557.     vim_free(buf->b_ml.ml_chunksize);
  558.     buf->b_ml.ml_chunksize = NULL;
  559. #endif
  560.     buf->b_ml.ml_mfp = NULL;
  561.  
  562.     /* Reset the "recovered" flag, give the ATTENTION prompt the next time
  563.      * this buffer is loaded. */
  564.     buf->b_flags &= ~BF_RECOVERED;
  565. }
  566.  
  567. /*
  568.  * Close all existing memlines and memfiles.
  569.  * Only used when exiting.
  570.  * When 'del_file' is TRUE, delete the memfiles.
  571.  */
  572.     void
  573. ml_close_all(del_file)
  574.     int        del_file;
  575. {
  576.     buf_T    *buf;
  577.  
  578.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  579.     ml_close(buf, del_file);
  580. #ifdef TEMPDIRNAMES
  581.     vim_deltempdir();        /* delete created temp directory */
  582. #endif
  583. }
  584.  
  585. /*
  586.  * Close all memfiles for not modified buffers.
  587.  * Only use just before exiting!
  588.  */
  589.     void
  590. ml_close_notmod()
  591. {
  592.     buf_T    *buf;
  593.  
  594.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  595.     if (!bufIsChanged(buf))
  596.         ml_close(buf, TRUE);    /* close all not-modified buffers */
  597. }
  598.  
  599. /*
  600.  * Update the timestamp in the .swp file.
  601.  * Used when the file has been written.
  602.  */
  603.     void
  604. ml_timestamp(buf)
  605.     buf_T    *buf;
  606. {
  607.     memfile_T    *mfp;
  608.     bhdr_T    *hp;
  609.     ZERO_BL    *b0p;
  610.  
  611.     mfp = buf->b_ml.ml_mfp;
  612.  
  613.     if (mfp == NULL || (hp = mf_get(mfp, (blocknr_T)0, 1)) == NULL)
  614.     return;
  615.     b0p = (ZERO_BL *)(hp->bh_data);
  616.     if (b0p->b0_id[0] != BLOCK0_ID0 || b0p->b0_id[1] != BLOCK0_ID1)
  617.     EMSG(_("E304: ml_timestamp: Didn't get block 0??"));
  618.     else
  619.     set_b0_fname(b0p, buf);
  620.     mf_put(mfp, hp, TRUE, FALSE);
  621. }
  622.  
  623. /*
  624.  * Write file name and timestamp into block 0 of a swap file.
  625.  * Also set buf->b_mtime.
  626.  * Don't use NameBuff[]!!!
  627.  */
  628.     static void
  629. set_b0_fname(b0p, buf)
  630.     ZERO_BL    *b0p;
  631.     buf_T    *buf;
  632. {
  633.     struct stat    st;
  634.  
  635.     if (buf->b_ffname == NULL)
  636.     b0p->b0_fname[0] = NUL;
  637.     else
  638.     {
  639. #if defined(MSDOS) || defined(MSWIN) || defined(AMIGA) || defined(RISCOS)
  640.     /* systems that cannot translate "~user" back into a path: copy the
  641.      * file name unmodified */
  642.     STRNCPY(b0p->b0_fname, buf->b_ffname, B0_FNAME_SIZE);
  643. #else
  644.     size_t    flen, ulen;
  645.     char_u    uname[B0_UNAME_SIZE];
  646.  
  647.     /*
  648.      * For a file under the home directory of the current user, we try to
  649.      * replace the home directory path with "~user". This helps when
  650.      * editing the same file on different machines over a network.
  651.      * First replace home dir path with "~/" with home_replace().
  652.      * Then insert the user name to get "~user/".
  653.      */
  654.     home_replace(NULL, buf->b_ffname, b0p->b0_fname, B0_FNAME_SIZE, TRUE);
  655.     if (b0p->b0_fname[0] == '~')
  656.     {
  657.         flen = STRLEN(b0p->b0_fname);
  658.         /* If there is no user name or it is too long, don't use "~/" */
  659.         if (get_user_name(uname, B0_UNAME_SIZE) == FAIL
  660.              || (ulen = STRLEN(uname)) + flen > B0_FNAME_SIZE - 1)
  661.         STRNCPY(b0p->b0_fname, buf->b_ffname, B0_FNAME_SIZE);
  662.         else
  663.         {
  664.         mch_memmove(b0p->b0_fname + ulen + 1, b0p->b0_fname + 1, flen);
  665.         mch_memmove(b0p->b0_fname + 1, uname, ulen);
  666.         }
  667.     }
  668. #endif
  669.     if (mch_stat((char *)buf->b_ffname, &st) >= 0)
  670.     {
  671.         long_to_char((long)st.st_mtime, b0p->b0_mtime);
  672. #ifdef CHECK_INODE
  673.         long_to_char((long)st.st_ino, b0p->b0_ino);
  674. #endif
  675.         buf_store_time(buf, &st, buf->b_ffname);
  676.         buf->b_mtime_read = buf->b_mtime;
  677.     }
  678.     else
  679.     {
  680.         long_to_char(0L, b0p->b0_mtime);
  681. #ifdef CHECK_INODE
  682.         long_to_char(0L, b0p->b0_ino);
  683. #endif
  684.         buf->b_mtime = 0;
  685.         buf->b_mtime_read = 0;
  686.         buf->b_orig_size = 0;
  687.         buf->b_orig_mode = 0;
  688.     }
  689.     }
  690. }
  691.  
  692. /*
  693.  * try to recover curbuf from the .swp file
  694.  */
  695.     void
  696. ml_recover()
  697. {
  698.     buf_T    *buf = NULL;
  699.     memfile_T    *mfp = NULL;
  700.     char_u    *fname;
  701.     bhdr_T    *hp = NULL;
  702.     ZERO_BL    *b0p;
  703.     PTR_BL    *pp;
  704.     DATA_BL    *dp;
  705.     infoptr_T    *ip;
  706.     blocknr_T    bnum;
  707.     int        page_count;
  708.     struct stat    org_stat, swp_stat;
  709.     int        len;
  710.     int        directly;
  711.     linenr_T    lnum;
  712.     char_u    *p;
  713.     int        i;
  714.     long    error;
  715.     int        cannot_open;
  716.     linenr_T    line_count;
  717.     int        has_error;
  718.     int        idx;
  719.     int        top;
  720.     int        txt_start;
  721.     off_t    size;
  722.     int        called_from_main;
  723.     int        serious_error = TRUE;
  724.     long    mtime;
  725.     int        attr;
  726.  
  727.     recoverymode = TRUE;
  728.     called_from_main = (curbuf->b_ml.ml_mfp == NULL);
  729.     attr = hl_attr(HLF_E);
  730. /*
  731.  * If the file name ends in ".sw?" we use it directly.
  732.  * Otherwise a search is done to find the swap file(s).
  733.  */
  734.     fname = curbuf->b_fname;
  735.     if (fname == NULL)            /* When there is no file name */
  736.     fname = (char_u *)"";
  737.     len = (int)STRLEN(fname);
  738.     if (len >= 4 &&
  739. #if defined(VMS) || defined(RISCOS)
  740.         STRNICMP(fname + len - 4, "_sw" , 3)
  741. #else
  742.         STRNICMP(fname + len - 4, ".sw" , 3)
  743. #endif
  744.         == 0)
  745.     {
  746.     directly = TRUE;
  747.     fname = vim_strsave(fname); /* make a copy for mf_open() */
  748.     }
  749.     else
  750.     {
  751.     directly = FALSE;
  752.  
  753.     /* count the number of matching swap files */
  754.     len = recover_names(&fname, FALSE, 0);
  755.     if (len == 0)            /* no swap files found */
  756.     {
  757.         EMSG2(_("E305: No swap file found for %s"), fname);
  758.         goto theend;
  759.     }
  760.     if (len == 1)            /* one swap file found, use it */
  761.         i = 1;
  762.     else                /* several swap files found, choose */
  763.     {
  764.         /* list the names of the swap files */
  765.         (void)recover_names(&fname, TRUE, 0);
  766.         msg_putchar('\n');
  767.         MSG_PUTS(_("Enter number of swap file to use (0 to quit): "));
  768.         i = get_number(FALSE);
  769.         if (i < 1 || i > len)
  770.         goto theend;
  771.     }
  772.     /* get the swap file name that will be used */
  773.     (void)recover_names(&fname, FALSE, i);
  774.     }
  775.     if (fname == NULL)
  776.     goto theend;            /* out of memory */
  777.  
  778.     /* When called from main() still need to initialize storage structure */
  779.     if (called_from_main && ml_open() == FAIL)
  780.     getout(1);
  781.  
  782. /*
  783.  * allocate a buffer structure (only the memline in it is really used)
  784.  */
  785.     buf = (buf_T *)alloc((unsigned)sizeof(buf_T));
  786.     if (buf == NULL)
  787.     {
  788.     vim_free(fname);
  789.     goto theend;
  790.     }
  791.  
  792. /*
  793.  * init fields in memline struct
  794.  */
  795.     buf->b_ml.ml_stack_size = 0;    /* no stack yet */
  796.     buf->b_ml.ml_stack = NULL;        /* no stack yet */
  797.     buf->b_ml.ml_stack_top = 0;        /* nothing in the stack */
  798.     buf->b_ml.ml_line_lnum = 0;        /* no cached line */
  799.     buf->b_ml.ml_locked = NULL;        /* no locked block */
  800.     buf->b_ml.ml_flags = 0;
  801.  
  802. /*
  803.  * open the memfile from the old swap file
  804.  */
  805.     p = vim_strsave(fname);        /* save fname for the message
  806.                        (mf_open() may free fname) */
  807.     mfp = mf_open(fname, O_RDONLY);    /* consumes fname! */
  808.     if (mfp == NULL || mfp->mf_fd < 0)
  809.     {
  810.     if (p != NULL)
  811.     {
  812.         EMSG2(_("E306: Cannot open %s"), p);
  813.         vim_free(p);
  814.     }
  815.     goto theend;
  816.     }
  817.     vim_free(p);
  818.     buf->b_ml.ml_mfp = mfp;
  819.  
  820.     /*
  821.      * The page size set in mf_open() might be different from the page size
  822.      * used in the swap file, we must get it from block 0.  But to read block
  823.      * 0 we need a page size.  Use the minimal size for block 0 here, it will
  824.      * be set to the real value below.
  825.      */
  826.     mfp->mf_page_size = MIN_SWAP_PAGE_SIZE;
  827.  
  828. /*
  829.  * try to read block 0
  830.  */
  831.     if ((hp = mf_get(mfp, (blocknr_T)0, 1)) == NULL)
  832.     {
  833.     msg_start();
  834.     MSG_PUTS_ATTR(_("Unable to read block 0 from "), attr | MSG_HIST);
  835.     msg_outtrans_attr(mfp->mf_fname, attr | MSG_HIST);
  836.     MSG_PUTS_ATTR(
  837.        _("\nMaybe no changes were made or Vim did not update the swap file."),
  838.         attr | MSG_HIST);
  839.     msg_end();
  840.     goto theend;
  841.     }
  842.     b0p = (ZERO_BL *)(hp->bh_data);
  843.     if (STRNCMP(b0p->b0_version, "VIM 3.0", 7) == 0)
  844.     {
  845.     msg_start();
  846.     msg_outtrans_attr(mfp->mf_fname, MSG_HIST);
  847.     MSG_PUTS_ATTR(_(" cannot be used with this version of Vim.\n"),
  848.                                     MSG_HIST);
  849.     MSG_PUTS_ATTR(_("Use Vim version 3.0.\n"), MSG_HIST);
  850.     msg_end();
  851.     goto theend;
  852.     }
  853.     if (b0p->b0_id[0] != BLOCK0_ID0 || b0p->b0_id[1] != BLOCK0_ID1)
  854.     {
  855.     EMSG2(_("E307: %s does not look like a Vim swap file"), mfp->mf_fname);
  856.     goto theend;
  857.     }
  858.     if (b0_magic_wrong(b0p))
  859.     {
  860.     msg_start();
  861.     msg_outtrans_attr(mfp->mf_fname, attr | MSG_HIST);
  862. #if defined(MSDOS) || defined(MSWIN)
  863.     if (STRNCMP(b0p->b0_hname, "PC ", 3) == 0)
  864.         MSG_PUTS_ATTR(_(" cannot be used with this version of Vim.\n"),
  865.                                  attr | MSG_HIST);
  866.     else
  867. #endif
  868.         MSG_PUTS_ATTR(_(" cannot be used on this computer.\n"),
  869.                                  attr | MSG_HIST);
  870.     MSG_PUTS_ATTR(_("The file was created on "), attr | MSG_HIST);
  871.     /* avoid going past the end of a currupted hostname */
  872.     b0p->b0_fname[0] = NUL;
  873.     MSG_PUTS_ATTR(b0p->b0_hname, attr | MSG_HIST);
  874.     MSG_PUTS_ATTR(_(",\nor the file has been damaged."), attr | MSG_HIST);
  875.     msg_end();
  876.     goto theend;
  877.     }
  878.     /*
  879.      * If we guessed the wrong page size, we have to recalculate the
  880.      * highest block number in the file.
  881.      */
  882.     if (mfp->mf_page_size != (unsigned)char_to_long(b0p->b0_page_size))
  883.     {
  884.     mfp->mf_page_size = (unsigned)char_to_long(b0p->b0_page_size);
  885.     if ((size = lseek(mfp->mf_fd, (off_t)0L, SEEK_END)) <= 0)
  886.         mfp->mf_blocknr_max = 0;        /* no file or empty file */
  887.     else
  888.         mfp->mf_blocknr_max = (blocknr_T)(size / mfp->mf_page_size);
  889.     mfp->mf_infile_count = mfp->mf_blocknr_max;
  890.     }
  891.  
  892. /*
  893.  * If .swp file name given directly, use name from swap file for buffer.
  894.  */
  895.     if (directly)
  896.     {
  897.     expand_env(b0p->b0_fname, NameBuff, MAXPATHL);
  898.     if (setfname(NameBuff, NULL, TRUE) == FAIL)
  899.         goto theend;
  900.     }
  901.  
  902.     home_replace(NULL, mfp->mf_fname, NameBuff, MAXPATHL, TRUE);
  903.     smsg((char_u *)_("Using swap file \"%s\""),
  904. #ifdef VMS
  905.         vms_fixfilename(NameBuff)
  906. #else
  907.         NameBuff
  908. #endif
  909.         );
  910.  
  911.     if (buf_spname(curbuf) != NULL)
  912.     STRCPY(NameBuff, buf_spname(curbuf));
  913.     else
  914.     home_replace(NULL, curbuf->b_ffname, NameBuff, MAXPATHL, TRUE);
  915.     smsg((char_u *)_("Original file \"%s\""),
  916. #ifdef VMS
  917.         vms_fixfilename(NameBuff)
  918. #else
  919.         NameBuff
  920. #endif
  921.         );
  922.     msg_putchar('\n');
  923.  
  924. /*
  925.  * check date of swap file and original file
  926.  */
  927.     mtime = char_to_long(b0p->b0_mtime);
  928.     if (curbuf->b_ffname != NULL
  929.         && mch_stat((char *)curbuf->b_ffname, &org_stat) != -1
  930.         && ((mch_stat((char *)mfp->mf_fname, &swp_stat) != -1
  931.             && org_stat.st_mtime > swp_stat.st_mtime)
  932.         || org_stat.st_mtime != mtime))
  933.     {
  934.     EMSG(_("E308: Warning: Original file may have been changed"));
  935.     }
  936.     out_flush();
  937.     mf_put(mfp, hp, FALSE, FALSE);    /* release block 0 */
  938.     hp = NULL;
  939.  
  940.     /*
  941.      * Now that we are sure that the file is going to be recovered, clear the
  942.      * contents of the current buffer.
  943.      */
  944.     while (!(curbuf->b_ml.ml_flags & ML_EMPTY))
  945.     ml_delete((linenr_T)1, FALSE);
  946.  
  947.     bnum = 1;        /* start with block 1 */
  948.     page_count = 1;    /* which is 1 page */
  949.     lnum = 0;        /* append after line 0 in curbuf */
  950.     line_count = 0;
  951.     idx = 0;        /* start with first index in block 1 */
  952.     error = 0;
  953.     buf->b_ml.ml_stack_top = 0;
  954.     buf->b_ml.ml_stack = NULL;
  955.     buf->b_ml.ml_stack_size = 0;    /* no stack yet */
  956.  
  957.     if (curbuf->b_ffname == NULL)
  958.     cannot_open = TRUE;
  959.     else
  960.     cannot_open = FALSE;
  961.  
  962.     serious_error = FALSE;
  963.     for ( ; !got_int; line_breakcheck())
  964.     {
  965.     if (hp != NULL)
  966.         mf_put(mfp, hp, FALSE, FALSE);    /* release previous block */
  967.  
  968.     /*
  969.      * get block
  970.      */
  971.     if ((hp = mf_get(mfp, (blocknr_T)bnum, page_count)) == NULL)
  972.     {
  973.         if (bnum == 1)
  974.         {
  975.         EMSG2(_("E309: Unable to read block 1 from %s"), mfp->mf_fname);
  976.         goto theend;
  977.         }
  978.         ++error;
  979.         ml_append(lnum++, (char_u *)_("???MANY LINES MISSING"),
  980.                                 (colnr_T)0, TRUE);
  981.     }
  982.     else        /* there is a block */
  983.     {
  984.         pp = (PTR_BL *)(hp->bh_data);
  985.         if (pp->pb_id == PTR_ID)        /* it is a pointer block */
  986.         {
  987.         /* check line count when using pointer block first time */
  988.         if (idx == 0 && line_count != 0)
  989.         {
  990.             for (i = 0; i < (int)pp->pb_count; ++i)
  991.             line_count -= pp->pb_pointer[i].pe_line_count;
  992.             if (line_count != 0)
  993.             {
  994.             ++error;
  995.             ml_append(lnum++, (char_u *)_("???LINE COUNT WRONG"),
  996.                                 (colnr_T)0, TRUE);
  997.             }
  998.         }
  999.  
  1000.         if (pp->pb_count == 0)
  1001.         {
  1002.             ml_append(lnum++, (char_u *)_("???EMPTY BLOCK"),
  1003.                                 (colnr_T)0, TRUE);
  1004.             ++error;
  1005.         }
  1006.         else if (idx < (int)pp->pb_count)    /* go a block deeper */
  1007.         {
  1008.             if (pp->pb_pointer[idx].pe_bnum < 0)
  1009.             {
  1010.             /*
  1011.              * Data block with negative block number.
  1012.              * Try to read lines from the original file.
  1013.              * This is slow, but it works.
  1014.              */
  1015.             if (!cannot_open)
  1016.             {
  1017.                 line_count = pp->pb_pointer[idx].pe_line_count;
  1018.                 if (readfile(curbuf->b_ffname, NULL, lnum,
  1019.                     pp->pb_pointer[idx].pe_old_lnum - 1,
  1020.                     line_count, NULL, 0) == FAIL)
  1021.                 cannot_open = TRUE;
  1022.                 else
  1023.                 lnum += line_count;
  1024.             }
  1025.             if (cannot_open)
  1026.             {
  1027.                 ++error;
  1028.                 ml_append(lnum++, (char_u *)_("???LINES MISSING"),
  1029.                                 (colnr_T)0, TRUE);
  1030.             }
  1031.             ++idx;        /* get same block again for next index */
  1032.             continue;
  1033.             }
  1034.  
  1035.             /*
  1036.              * going one block deeper in the tree
  1037.              */
  1038.             if ((top = ml_add_stack(buf)) < 0)    /* new entry in stack */
  1039.             {
  1040.             ++error;
  1041.             break;            /* out of memory */
  1042.             }
  1043.             ip = &(buf->b_ml.ml_stack[top]);
  1044.             ip->ip_bnum = bnum;
  1045.             ip->ip_index = idx;
  1046.  
  1047.             bnum = pp->pb_pointer[idx].pe_bnum;
  1048.             line_count = pp->pb_pointer[idx].pe_line_count;
  1049.             page_count = pp->pb_pointer[idx].pe_page_count;
  1050.             continue;
  1051.         }
  1052.         }
  1053.         else        /* not a pointer block */
  1054.         {
  1055.         dp = (DATA_BL *)(hp->bh_data);
  1056.         if (dp->db_id != DATA_ID)    /* block id wrong */
  1057.         {
  1058.             if (bnum == 1)
  1059.             {
  1060.             EMSG2(_("E310: Block 1 ID wrong (%s not a .swp file?)"),
  1061.                                    mfp->mf_fname);
  1062.             goto theend;
  1063.             }
  1064.             ++error;
  1065.             ml_append(lnum++, (char_u *)_("???BLOCK MISSING"),
  1066.                                 (colnr_T)0, TRUE);
  1067.         }
  1068.         else
  1069.         {
  1070.             /*
  1071.              * it is a data block
  1072.              * Append all the lines in this block
  1073.              */
  1074.             has_error = FALSE;
  1075.             /*
  1076.              * check length of block
  1077.              * if wrong, use length in pointer block
  1078.              */
  1079.             if (page_count * mfp->mf_page_size != dp->db_txt_end)
  1080.             {
  1081.             ml_append(lnum++, (char_u *)_("??? from here until ???END lines may be messed up"),
  1082.                                 (colnr_T)0, TRUE);
  1083.             ++error;
  1084.             has_error = TRUE;
  1085.             dp->db_txt_end = page_count * mfp->mf_page_size;
  1086.             }
  1087.  
  1088.             /* make sure there is a NUL at the end of the block */
  1089.             *((char_u *)dp + dp->db_txt_end - 1) = NUL;
  1090.  
  1091.             /*
  1092.              * check number of lines in block
  1093.              * if wrong, use count in data block
  1094.              */
  1095.             if (line_count != dp->db_line_count)
  1096.             {
  1097.             ml_append(lnum++, (char_u *)_("??? from here until ???END lines may have been inserted/deleted"),
  1098.                                 (colnr_T)0, TRUE);
  1099.             ++error;
  1100.             has_error = TRUE;
  1101.             }
  1102.  
  1103.             for (i = 0; i < dp->db_line_count; ++i)
  1104.             {
  1105.             txt_start = (dp->db_index[i] & DB_INDEX_MASK);
  1106.             if (txt_start <= HEADER_SIZE
  1107.                       || txt_start >= (int)dp->db_txt_end)
  1108.             {
  1109.                 p = (char_u *)"???";
  1110.                 ++error;
  1111.             }
  1112.             else
  1113.                 p = (char_u *)dp + txt_start;
  1114.             ml_append(lnum++, p, (colnr_T)0, TRUE);
  1115.             }
  1116.             if (has_error)
  1117.             ml_append(lnum++, (char_u *)_("???END"), (colnr_T)0, TRUE);
  1118.         }
  1119.         }
  1120.     }
  1121.  
  1122.     if (buf->b_ml.ml_stack_top == 0)    /* finished */
  1123.         break;
  1124.  
  1125.     /*
  1126.      * go one block up in the tree
  1127.      */
  1128.     ip = &(buf->b_ml.ml_stack[--(buf->b_ml.ml_stack_top)]);
  1129.     bnum = ip->ip_bnum;
  1130.     idx = ip->ip_index + 1;        /* go to next index */
  1131.     page_count = 1;
  1132.     }
  1133.  
  1134.     /*
  1135.      * The dummy line from the empty buffer will now be after the last line in
  1136.      * the buffer. Delete it.
  1137.      */
  1138.     ml_delete(curbuf->b_ml.ml_line_count, FALSE);
  1139.     curbuf->b_flags |= BF_RECOVERED;
  1140.  
  1141.     recoverymode = FALSE;
  1142.     if (got_int)
  1143.     EMSG(_("E311: Recovery Interrupted"));
  1144.     else if (error)
  1145.     EMSG(_("E312: Errors detected while recovering; look for lines starting with ???"));
  1146.     else
  1147.     {
  1148.     MSG(_("Recovery completed. You should check if everything is OK."));
  1149.     MSG_PUTS(_("\n(You might want to write out this file under another name\n"));
  1150.     MSG_PUTS(_("and run diff with the original file to check for changes)\n"));
  1151.     MSG_PUTS(_("Delete the .swp file afterwards.\n\n"));
  1152.     cmdline_row = msg_row;
  1153.     }
  1154.     redraw_curbuf_later(NOT_VALID);
  1155.  
  1156. theend:
  1157.     recoverymode = FALSE;
  1158.     if (mfp != NULL)
  1159.     {
  1160.     if (hp != NULL)
  1161.         mf_put(mfp, hp, FALSE, FALSE);
  1162.     mf_close(mfp, FALSE);        /* will also vim_free(mfp->mf_fname) */
  1163.     }
  1164.     vim_free(buf);
  1165.     if (serious_error && called_from_main)
  1166.     ml_close(curbuf, TRUE);
  1167. #ifdef FEAT_AUTOCMD
  1168.     else
  1169.     {
  1170.     apply_autocmds(EVENT_BUFREADPOST, NULL, curbuf->b_fname, FALSE, curbuf);
  1171.     apply_autocmds(EVENT_BUFWINENTER, NULL, curbuf->b_fname, FALSE, curbuf);
  1172.     }
  1173. #endif
  1174.     return;
  1175. }
  1176.  
  1177. /*
  1178.  * Find the names of swap files in current directory and the directory given
  1179.  * with the 'directory' option.
  1180.  *
  1181.  * Used to:
  1182.  * - list the swap files for "vim -r"
  1183.  * - count the number of swap files when recovering
  1184.  * - list the swap files when recovering
  1185.  * - find the name of the n'th swap file when recovering
  1186.  */
  1187.     int
  1188. recover_names(fname, list, nr)
  1189.     char_u    **fname;    /* base for swap file name */
  1190.     int        list;        /* when TRUE, list the swap file names */
  1191.     int        nr;        /* when non-zero, return nr'th swap file name */
  1192. {
  1193.     int        num_names;
  1194.     char_u    *(names[6]);
  1195.     char_u    *tail;
  1196.     char_u    *p;
  1197.     int        num_files;
  1198.     int        file_count = 0;
  1199.     char_u    **files;
  1200.     int        i;
  1201.     char_u    *dirp;
  1202.     char_u    *dir_name;
  1203.  
  1204.     if (list)
  1205.     {
  1206.         /* use msg() to start the scrolling properly */
  1207.     msg((char_u *)_("Swap files found:"));
  1208.     msg_putchar('\n');
  1209.     }
  1210.  
  1211.     /*
  1212.      * Do the loop for every directory in 'directory'.
  1213.      * First allocate some memory to put the directory name in.
  1214.      */
  1215.     dir_name = alloc((unsigned)STRLEN(p_dir) + 1);
  1216.     dirp = p_dir;
  1217.     while (dir_name != NULL && *dirp)
  1218.     {
  1219.     /*
  1220.      * Isolate a directory name from *dirp and put it in dir_name (we know
  1221.      * it is large enough, so use 31000 for length).
  1222.      * Advance dirp to next directory name.
  1223.      */
  1224.     (void)copy_option_part(&dirp, dir_name, 31000, ",");
  1225.  
  1226.     if (dir_name[0] == '.' && dir_name[1] == NUL)    /* check current dir */
  1227.     {
  1228.         if (fname == NULL || *fname == NULL)
  1229.         {
  1230. #ifdef VMS
  1231.         names[0] = vim_strsave((char_u *)"*_sw%");
  1232. #else
  1233. # ifdef RISCOS
  1234.         names[0] = vim_strsave((char_u *)"*_sw#");
  1235. # else
  1236.         names[0] = vim_strsave((char_u *)"*.sw?");
  1237. # endif
  1238. #endif
  1239. #ifdef UNIX
  1240.         /* for Unix names starting with a dot are special */
  1241.         names[1] = vim_strsave((char_u *)".*.sw?");
  1242.         names[2] = vim_strsave((char_u *)".sw?");
  1243.         num_names = 3;
  1244. #else
  1245. # ifdef VMS
  1246.         names[1] = vim_strsave((char_u *)".*_sw%");
  1247.         num_names = 2;
  1248. # else
  1249.         num_names = 1;
  1250. # endif
  1251. #endif
  1252.         }
  1253.         else
  1254.         num_names = recov_file_names(names, *fname, TRUE);
  1255.     }
  1256.     else                /* check directory dir_name */
  1257.     {
  1258.         if (fname == NULL || *fname == NULL)
  1259.         {
  1260. #ifdef VMS
  1261.         names[0] = concat_fnames(dir_name, (char_u *)"*_sw%", TRUE);
  1262. #else
  1263. # ifdef RISCOS
  1264.         names[0] = concat_fnames(dir_name, (char_u *)"*_sw#", TRUE);
  1265. # else
  1266.         names[0] = concat_fnames(dir_name, (char_u *)"*.sw?", TRUE);
  1267. # endif
  1268. #endif
  1269. #ifdef UNIX
  1270.         /* for Unix names starting with a dot are special */
  1271.         names[1] = concat_fnames(dir_name, (char_u *)".*.sw?", TRUE);
  1272.         names[2] = concat_fnames(dir_name, (char_u *)".sw?", TRUE);
  1273.         num_names = 3;
  1274. #else
  1275. # ifdef VMS
  1276.         names[1] = concat_fnames(dir_name, (char_u *)".*_sw%", TRUE);
  1277.         num_names = 2;
  1278. # else
  1279.         num_names = 1;
  1280. # endif
  1281. #endif
  1282.         }
  1283.         else
  1284.         {
  1285. #if defined(UNIX) || defined(WIN3264)
  1286.         p = dir_name + STRLEN(dir_name);
  1287.         if (vim_ispathsep(p[-1]) && p[-1] == p[-2])
  1288.         {
  1289.             /* Ends with '//', Use Full path for swap name */
  1290.             tail = make_percent_swname(dir_name, *fname);
  1291.         }
  1292.         else
  1293. #endif
  1294.         {
  1295.             tail = gettail(*fname);
  1296.             tail = concat_fnames(dir_name, tail, TRUE);
  1297.         }
  1298.         if (tail == NULL)
  1299.             num_names = 0;
  1300.         else
  1301.         {
  1302.             num_names = recov_file_names(names, tail, FALSE);
  1303.             vim_free(tail);
  1304.         }
  1305.         }
  1306.     }
  1307.  
  1308.         /* check for out-of-memory */
  1309.     for (i = 0; i < num_names; ++i)
  1310.     {
  1311.         if (names[i] == NULL)
  1312.         {
  1313.         for (i = 0; i < num_names; ++i)
  1314.             vim_free(names[i]);
  1315.         num_names = 0;
  1316.         }
  1317.     }
  1318.     if (num_names == 0)
  1319.         num_files = 0;
  1320.     else if (expand_wildcards(num_names, names, &num_files, &files,
  1321.                            EW_FILE|EW_SILENT) == FAIL)
  1322.         num_files = 0;
  1323.  
  1324.     /*
  1325.      * When no swap file found, wildcard expansion might have failed (e.g.
  1326.      * not able to execute the shell).
  1327.      * Try finding a swap file by simply adding ".swp" to the file name.
  1328.      */
  1329.     if (*dirp == NUL && file_count + num_files == 0
  1330.                        && fname != NULL && *fname != NULL)
  1331.     {
  1332.         struct stat        st;
  1333.         char_u        *swapname;
  1334.  
  1335. #if defined(VMS) || defined(RISCOS)
  1336.         swapname = modname(*fname, (char_u *)"_swp", FALSE);
  1337. #else
  1338.         swapname = modname(*fname, (char_u *)".swp", TRUE);
  1339. #endif
  1340.         if (swapname != NULL)
  1341.         {
  1342.         if (mch_stat((char *)swapname, &st) != -1)        /* It exists! */
  1343.         {
  1344.             files = (char_u **)alloc((unsigned)sizeof(char_u *));
  1345.             if (files != NULL)
  1346.             {
  1347.             files[0] = swapname;
  1348.             swapname = NULL;
  1349.             num_files = 1;
  1350.             }
  1351.         }
  1352.         vim_free(swapname);
  1353.         }
  1354.     }
  1355.  
  1356.     /*
  1357.      * remove swapfile name of the current buffer, it must be ignored
  1358.      */
  1359.     if (curbuf->b_ml.ml_mfp != NULL
  1360.                    && (p = curbuf->b_ml.ml_mfp->mf_fname) != NULL)
  1361.     {
  1362.         for (i = 0; i < num_files; ++i)
  1363.         if (fullpathcmp(p, files[i], TRUE) & FPC_SAME)
  1364.         {
  1365.             vim_free(files[i]);
  1366.             --num_files;
  1367.             for ( ; i < num_files; ++i)
  1368.             files[i] = files[i + 1];
  1369.         }
  1370.     }
  1371.     if (nr)
  1372.     {
  1373.         file_count += num_files;
  1374.         if (nr <= file_count)
  1375.         {
  1376.         *fname = vim_strsave(files[nr - 1 + num_files - file_count]);
  1377.         dirp = (char_u *)"";            /* stop searching */
  1378.         }
  1379.     }
  1380.     else if (list)
  1381.     {
  1382.         if (dir_name[0] == '.' && dir_name[1] == NUL)
  1383.         {
  1384.         if (fname == NULL || *fname == NULL)
  1385.             MSG_PUTS(_("   In current directory:\n"));
  1386.         else
  1387.             MSG_PUTS(_("   Using specified name:\n"));
  1388.         }
  1389.         else
  1390.         {
  1391.         MSG_PUTS(_("   In directory "));
  1392.         msg_home_replace(dir_name);
  1393.         MSG_PUTS(":\n");
  1394.         }
  1395.  
  1396.         if (num_files)
  1397.         {
  1398.         for (i = 0; i < num_files; ++i)
  1399.         {
  1400.             /* print the swap file name */
  1401.             msg_outnum((long)++file_count);
  1402.             MSG_PUTS(".    ");
  1403.             msg_puts(gettail(files[i]));
  1404.             msg_putchar('\n');
  1405.             (void)swapfile_info(files[i]);
  1406.         }
  1407.         }
  1408.         else
  1409.         MSG_PUTS(_("      -- none --\n"));
  1410.         out_flush();
  1411.     }
  1412.     else
  1413.         file_count += num_files;
  1414.  
  1415.     for (i = 0; i < num_names; ++i)
  1416.         vim_free(names[i]);
  1417.     FreeWild(num_files, files);
  1418.     }
  1419.     vim_free(dir_name);
  1420.     return file_count;
  1421. }
  1422.  
  1423. #if defined(UNIX) || defined(WIN3264)  /* Need _very_ long file names */
  1424. /*
  1425.  * Append the full path to name with path separators made into percent
  1426.  * signs, to dir. An unnamed buffer is handled as "" (<currentdir>/"")
  1427.  */
  1428.     static char_u *
  1429. make_percent_swname(dir, name)
  1430.     char_u    *dir;
  1431.     char_u    *name;
  1432. {
  1433.     char_u *d, *s, *f, *p;
  1434.  
  1435.     f = fix_fname(name != NULL ? name : (char_u *) "");
  1436.     d = NULL;
  1437.     if (f != NULL)
  1438.     {
  1439.     s = alloc((unsigned)(STRLEN(f) + 1));
  1440.     if (s != NULL)
  1441.     {
  1442.         for (d = s, p = f; *p; p++, d++)
  1443.         *d = vim_ispathsep(*p) ? '%' : *p;
  1444.         *d = 0;
  1445.         d = concat_fnames(dir, s, TRUE);
  1446.         vim_free(s);
  1447.     }
  1448.     vim_free(f);
  1449.     }
  1450.     return d;
  1451. }
  1452. #endif
  1453.  
  1454. #if (defined(UNIX) || defined(__EMX__) || defined(VMS)) && (defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG))
  1455. static int process_still_running;
  1456. #endif
  1457.  
  1458. /*
  1459.  * Give information about an existing swap file
  1460.  * Returns timestamp (0 when unknown).
  1461.  */
  1462.     static time_t
  1463. swapfile_info(fname)
  1464.     char_u    *fname;
  1465. {
  1466.     struct stat        st;
  1467.     int            fd;
  1468.     struct block0   b0;
  1469.     time_t        x = (time_t)0;
  1470. #ifdef UNIX
  1471.     char_u        uname[B0_UNAME_SIZE];
  1472. #endif
  1473.  
  1474.     /* print the swap file date */
  1475.     if (mch_stat((char *)fname, &st) != -1)
  1476.     {
  1477. #ifdef UNIX
  1478.     /* print name of owner of the file */
  1479.     if (mch_get_uname(st.st_uid, uname, B0_UNAME_SIZE) == OK)
  1480.     {
  1481.         MSG_PUTS(_("          owned by: "));
  1482.         msg_outtrans(uname);
  1483.         MSG_PUTS(_("   dated: "));
  1484.     }
  1485.     else
  1486. #endif
  1487.         MSG_PUTS(_("             dated: "));
  1488.     x = st.st_mtime;            /* Manx C can't do &st.st_mtime */
  1489.     MSG_PUTS(ctime(&x));            /* includes '\n' */
  1490.  
  1491.     }
  1492.  
  1493.     /*
  1494.      * print the original file name
  1495.      */
  1496.     fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
  1497.     if (fd >= 0)
  1498.     {
  1499.     if (read(fd, (char *)&b0, sizeof(b0)) == sizeof(b0))
  1500.     {
  1501.         if (STRNCMP(b0.b0_version, "VIM 3.0", 7) == 0)
  1502.         {
  1503.         MSG_PUTS(_("         [from Vim version 3.0]"));
  1504.         }
  1505.         else if (b0.b0_id[0] != BLOCK0_ID0 || b0.b0_id[1] != BLOCK0_ID1)
  1506.         {
  1507.         MSG_PUTS(_("         [does not look like a Vim swap file]"));
  1508.         }
  1509.         else
  1510.         {
  1511.         MSG_PUTS(_("         file name: "));
  1512.         if (b0.b0_fname[0] == NUL)
  1513.             MSG_PUTS(_("[No File]"));
  1514.         else
  1515.             msg_outtrans(
  1516. #ifdef VMS
  1517.                 vms_fixfilename(b0.b0_fname)
  1518. #else
  1519.                 b0.b0_fname
  1520. #endif
  1521.                 );
  1522.  
  1523.         MSG_PUTS(_("\n          modified: "));
  1524.         MSG_PUTS(b0.b0_dirty ? _("YES") : _("no"));
  1525.  
  1526.         if (*(b0.b0_uname) != NUL)
  1527.         {
  1528.             MSG_PUTS(_("\n         user name: "));
  1529.             msg_outtrans(b0.b0_uname);
  1530.         }
  1531.  
  1532.         if (*(b0.b0_hname) != NUL)
  1533.         {
  1534.             if (*(b0.b0_uname) != NUL)
  1535.             MSG_PUTS(_("   host name: "));
  1536.             else
  1537.             MSG_PUTS(_("\n         host name: "));
  1538.             msg_outtrans(b0.b0_hname);
  1539.         }
  1540.  
  1541.         if (char_to_long(b0.b0_pid) != 0L)
  1542.         {
  1543.             MSG_PUTS(_("\n        process ID: "));
  1544.             msg_outnum(char_to_long(b0.b0_pid));
  1545. #if defined(UNIX) || defined(__EMX__)
  1546.             /* EMX kill() not working correctly, it seems */
  1547.             if (kill((pid_t)char_to_long(b0.b0_pid), 0) == 0)
  1548.             {
  1549.             MSG_PUTS(_(" (still running)"));
  1550. # if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
  1551.             process_still_running = TRUE;
  1552. # endif
  1553.             }
  1554. #endif
  1555.         }
  1556.  
  1557.         if (b0_magic_wrong(&b0))
  1558.         {
  1559. #if defined(MSDOS) || defined(MSWIN)
  1560.             if (STRNCMP(b0.b0_hname, "PC ", 3) == 0)
  1561.             MSG_PUTS(_("\n         [not usable with this version of Vim]"));
  1562.             else
  1563. #endif
  1564.             MSG_PUTS(_("\n         [not usable on this computer]"));
  1565.         }
  1566.         }
  1567.     }
  1568.     else
  1569.         MSG_PUTS(_("         [cannot be read]"));
  1570.     close(fd);
  1571.     }
  1572.     else
  1573.     MSG_PUTS(_("         [cannot be opened]"));
  1574.     msg_putchar('\n');
  1575.  
  1576.     return x;
  1577. }
  1578.  
  1579.     static int
  1580. recov_file_names(names, path, prepend_dot)
  1581.     char_u    **names;
  1582.     char_u    *path;
  1583.     int        prepend_dot;
  1584. {
  1585.     int        num_names;
  1586.  
  1587. #ifdef SHORT_FNAME
  1588.     /*
  1589.      * (MS-DOS) always short names
  1590.      */
  1591.     names[0] = modname(path, (char_u *)".sw?", FALSE);
  1592.     num_names = 1;
  1593. #else /* !SHORT_FNAME */
  1594.     /*
  1595.      * (Win32 and Win64) never short names, but do prepend a dot.
  1596.      * (Not MS-DOS or Win32 or Win64) maybe short name, maybe not: Try both.
  1597.      * Only use the short name if it is different.
  1598.      */
  1599.     char_u    *p;
  1600.     int        i;
  1601. # ifndef WIN3264
  1602.     int        shortname = curbuf->b_shortname;
  1603.  
  1604.     curbuf->b_shortname = FALSE;
  1605. # endif
  1606.  
  1607.     num_names = 0;
  1608.  
  1609.     /*
  1610.      * May also add the file name with a dot prepended, for swap file in same
  1611.      * dir as original file.
  1612.      */
  1613.     if (prepend_dot)
  1614.     {
  1615.     names[num_names] = modname(path, (char_u *)".sw?", TRUE);
  1616.     if (names[num_names] == NULL)
  1617.         goto end;
  1618.     ++num_names;
  1619.     }
  1620.  
  1621.     /*
  1622.      * Form the normal swap file name pattern by appending ".sw?".
  1623.      */
  1624. #ifdef VMS
  1625.     names[num_names] = concat_fnames(path, (char_u *)"_sw%", FALSE);
  1626. #else
  1627. # ifdef RISCOS
  1628.     names[num_names] = concat_fnames(path, (char_u *)"_sw#", FALSE);
  1629. # else
  1630.     names[num_names] = concat_fnames(path, (char_u *)".sw?", FALSE);
  1631. # endif
  1632. #endif
  1633.     if (names[num_names] == NULL)
  1634.     goto end;
  1635.     if (num_names >= 1)        /* check if we have the same name twice */
  1636.     {
  1637.     p = names[num_names - 1];
  1638.     i = (int)STRLEN(names[num_names - 1]) - (int)STRLEN(names[num_names]);
  1639.     if (i > 0)
  1640.         p += i;        /* file name has been expanded to full path */
  1641.  
  1642.     if (STRCMP(p, names[num_names]) != 0)
  1643.         ++num_names;
  1644.     else
  1645.         vim_free(names[num_names]);
  1646.     }
  1647.     else
  1648.     ++num_names;
  1649.  
  1650. # ifndef WIN3264
  1651.     /*
  1652.      * Also try with 'shortname' set, in case the file is on a DOS filesystem.
  1653.      */
  1654.     curbuf->b_shortname = TRUE;
  1655. #ifdef VMS
  1656.     names[num_names] = modname(path, (char_u *)"_sw%", FALSE);
  1657. #else
  1658. # ifdef RISCOS
  1659.     names[num_names] = modname(path, (char_u *)"_sw#", FALSE);
  1660. # else
  1661.     names[num_names] = modname(path, (char_u *)".sw?", FALSE);
  1662. # endif
  1663. #endif
  1664.     if (names[num_names] == NULL)
  1665.     goto end;
  1666.  
  1667.     /*
  1668.      * Remove the one from 'shortname', if it's the same as with 'noshortname'.
  1669.      */
  1670.     p = names[num_names];
  1671.     i = STRLEN(names[num_names]) - STRLEN(names[num_names - 1]);
  1672.     if (i > 0)
  1673.     p += i;        /* file name has been expanded to full path */
  1674.     if (STRCMP(names[num_names - 1], p) == 0)
  1675.     vim_free(names[num_names]);
  1676.     else
  1677.     ++num_names;
  1678. # endif
  1679.  
  1680. end:
  1681. # ifndef WIN3264
  1682.     curbuf->b_shortname = shortname;
  1683. # endif
  1684.  
  1685. #endif /* !SHORT_FNAME */
  1686.  
  1687.     return num_names;
  1688. }
  1689.  
  1690. /*
  1691.  * sync all memlines
  1692.  *
  1693.  * If 'check_file' is TRUE, check if original file exists and was not changed.
  1694.  * If 'check_char' is TRUE, stop syncing when character becomes available, but
  1695.  * always sync at least one block.
  1696.  */
  1697.     void
  1698. ml_sync_all(check_file, check_char)
  1699.     int        check_file;
  1700.     int        check_char;
  1701. {
  1702.     buf_T        *buf;
  1703.     struct stat        st;
  1704.  
  1705.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  1706.     {
  1707.     if (buf->b_ml.ml_mfp == NULL || buf->b_ml.ml_mfp->mf_fname == NULL)
  1708.         continue;                /* no file */
  1709.  
  1710.     ml_flush_line(buf);            /* flush buffered line */
  1711.                         /* flush locked block */
  1712.     (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH);
  1713.     if (bufIsChanged(buf) && check_file && mf_need_trans(buf->b_ml.ml_mfp)
  1714.                              && buf->b_ffname != NULL)
  1715.     {
  1716.         /*
  1717.          * If the original file does not exist anymore or has been changed
  1718.          * call ml_preserve() to get rid of all negative numbered blocks.
  1719.          */
  1720.         if (mch_stat((char *)buf->b_ffname, &st) == -1
  1721.             || st.st_mtime != buf->b_mtime_read
  1722.             || (size_t)st.st_size != buf->b_orig_size)
  1723.         {
  1724.         ml_preserve(buf, FALSE);
  1725.         did_check_timestamps = FALSE;
  1726.         need_check_timestamps = TRUE;    /* give message later */
  1727.         }
  1728.     }
  1729.     if (buf->b_ml.ml_mfp->mf_dirty)
  1730.     {
  1731.         (void)mf_sync(buf->b_ml.ml_mfp, (check_char ? MFS_STOP : 0)
  1732.                     | (bufIsChanged(buf) ? MFS_FLUSH : 0));
  1733.         if (check_char && ui_char_avail())    /* character available now */
  1734.         break;
  1735.     }
  1736.     }
  1737. }
  1738.  
  1739. /*
  1740.  * sync one buffer, including negative blocks
  1741.  *
  1742.  * after this all the blocks are in the swap file
  1743.  *
  1744.  * Used for the :preserve command and when the original file has been
  1745.  * changed or deleted.
  1746.  *
  1747.  * when message is TRUE the success of preserving is reported
  1748.  */
  1749.     void
  1750. ml_preserve(buf, message)
  1751.     buf_T    *buf;
  1752.     int        message;
  1753. {
  1754.     bhdr_T    *hp;
  1755.     linenr_T    lnum;
  1756.     memfile_T    *mfp = buf->b_ml.ml_mfp;
  1757.     int        status;
  1758.     int        got_int_save = got_int;
  1759.  
  1760.     if (mfp == NULL || mfp->mf_fname == NULL)
  1761.     {
  1762.     if (message)
  1763.         EMSG(_("E313: Cannot preserve, there is no swap file"));
  1764.     return;
  1765.     }
  1766.  
  1767.     /* We only want to stop when interrupted here, not when interrupted
  1768.      * before. */
  1769.     got_int = FALSE;
  1770.  
  1771.     ml_flush_line(buf);                    /* flush buffered line */
  1772.     (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH); /* flush locked block */
  1773.     status = mf_sync(mfp, MFS_ALL | MFS_FLUSH);
  1774.  
  1775.     /* stack is invalid after mf_sync(.., MFS_ALL) */
  1776.     buf->b_ml.ml_stack_top = 0;
  1777.  
  1778.     /*
  1779.      * Some of the data blocks may have been changed from negative to
  1780.      * positive block number. In that case the pointer blocks need to be
  1781.      * updated.
  1782.      *
  1783.      * We don't know in which pointer block the references are, so we visit
  1784.      * all data blocks until there are no more translations to be done (or
  1785.      * we hit the end of the file, which can only happen in case a write fails,
  1786.      * e.g. when file system if full).
  1787.      * ml_find_line() does the work by translating the negative block numbers
  1788.      * when getting the first line of each data block.
  1789.      */
  1790.     if (mf_need_trans(mfp) && !got_int)
  1791.     {
  1792.     lnum = 1;
  1793.     while (mf_need_trans(mfp) && lnum <= buf->b_ml.ml_line_count)
  1794.     {
  1795.         hp = ml_find_line(buf, lnum, ML_FIND);
  1796.         if (hp == NULL)
  1797.         {
  1798.         status = FAIL;
  1799.         goto theend;
  1800.         }
  1801.         CHECK(buf->b_ml.ml_locked_low != lnum, "low != lnum");
  1802.         lnum = buf->b_ml.ml_locked_high + 1;
  1803.     }
  1804.     (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH);    /* flush locked block */
  1805.     /* sync the updated pointer blocks */
  1806.     if (mf_sync(mfp, MFS_ALL | MFS_FLUSH) == FAIL)
  1807.         status = FAIL;
  1808.     buf->b_ml.ml_stack_top = 0;        /* stack is invalid now */
  1809.     }
  1810. theend:
  1811.     got_int |= got_int_save;
  1812.  
  1813.     if (message)
  1814.     {
  1815.     if (status == OK)
  1816.         MSG(_("File preserved"));
  1817.     else
  1818.         EMSG(_("E314: Preserve failed"));
  1819.     }
  1820. }
  1821.  
  1822. /*
  1823.  * NOTE: The pointer returned by the ml_get_*() functions only remains valid
  1824.  * until the next call!
  1825.  *  line1 = ml_get(1);
  1826.  *  line2 = ml_get(2);    // line1 is now invalid!
  1827.  * Make a copy of the line if necessary.
  1828.  */
  1829. /*
  1830.  * get a pointer to a (read-only copy of a) line
  1831.  *
  1832.  * On failure an error message is given and IObuff is returned (to avoid
  1833.  * having to check for error everywhere).
  1834.  */
  1835.     char_u  *
  1836. ml_get(lnum)
  1837.     linenr_T    lnum;
  1838. {
  1839.     return ml_get_buf(curbuf, lnum, FALSE);
  1840. }
  1841.  
  1842. /*
  1843.  * ml_get_pos: get pointer to position 'pos'
  1844.  */
  1845.     char_u *
  1846. ml_get_pos(pos)
  1847.     pos_T    *pos;
  1848. {
  1849.     return (ml_get_buf(curbuf, pos->lnum, FALSE) + pos->col);
  1850. }
  1851.  
  1852. /*
  1853.  * ml_get_curline: get pointer to cursor line.
  1854.  */
  1855.     char_u *
  1856. ml_get_curline()
  1857. {
  1858.     return ml_get_buf(curbuf, curwin->w_cursor.lnum, FALSE);
  1859. }
  1860.  
  1861. /*
  1862.  * ml_get_cursor: get pointer to cursor position
  1863.  */
  1864.     char_u *
  1865. ml_get_cursor()
  1866. {
  1867.     return (ml_get_buf(curbuf, curwin->w_cursor.lnum, FALSE) +
  1868.                             curwin->w_cursor.col);
  1869. }
  1870.  
  1871. /*
  1872.  * get a pointer to a line in a specific buffer
  1873.  *
  1874.  * "will_change": if TRUE mark the buffer dirty (chars in the line will be
  1875.  * changed)
  1876.  */
  1877.     char_u  *
  1878. ml_get_buf(buf, lnum, will_change)
  1879.     buf_T    *buf;
  1880.     linenr_T    lnum;
  1881.     int        will_change;        /* line will be changed */
  1882. {
  1883.     bhdr_T    *hp;
  1884.     DATA_BL *dp;
  1885.     char_u  *ptr;
  1886.  
  1887.     if (lnum > buf->b_ml.ml_line_count)    /* invalid line number */
  1888.     {
  1889.     EMSGN(_("E315: ml_get: invalid lnum: %ld"), lnum);
  1890. errorret:
  1891.     STRCPY(IObuff, "???");
  1892.     return IObuff;
  1893.     }
  1894.     if (lnum <= 0)            /* pretend line 0 is line 1 */
  1895.     lnum = 1;
  1896.  
  1897.     if (buf->b_ml.ml_mfp == NULL)    /* there are no lines */
  1898.     return (char_u *)"";
  1899.  
  1900. /*
  1901.  * See if it is the same line as requested last time.
  1902.  * Otherwise may need to flush last used line.
  1903.  */
  1904.     if (buf->b_ml.ml_line_lnum != lnum)
  1905.     {
  1906.     ml_flush_line(buf);
  1907.  
  1908.     /*
  1909.      * Find the data block containing the line.
  1910.      * This also fills the stack with the blocks from the root to the data
  1911.      * block and releases any locked block.
  1912.      */
  1913.     if ((hp = ml_find_line(buf, lnum, ML_FIND)) == NULL)
  1914.     {
  1915.         EMSGN(_("E316: ml_get: cannot find line %ld"), lnum);
  1916.         goto errorret;
  1917.     }
  1918.  
  1919.     dp = (DATA_BL *)(hp->bh_data);
  1920.  
  1921.     ptr = (char_u *)dp + ((dp->db_index[lnum - buf->b_ml.ml_locked_low]) & DB_INDEX_MASK);
  1922.     buf->b_ml.ml_line_ptr = ptr;
  1923.     buf->b_ml.ml_line_lnum = lnum;
  1924.     buf->b_ml.ml_flags &= ~ML_LINE_DIRTY;
  1925.     }
  1926.     if (will_change)
  1927.     buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
  1928.  
  1929.     return buf->b_ml.ml_line_ptr;
  1930. }
  1931.  
  1932. /*
  1933.  * Check if a line that was just obtained by a call to ml_get
  1934.  * is in allocated memory.
  1935.  */
  1936.     int
  1937. ml_line_alloced()
  1938. {
  1939.     return (curbuf->b_ml.ml_flags & ML_LINE_DIRTY);
  1940. }
  1941.  
  1942. /*
  1943.  * append a line after lnum (may be 0 to insert a line in front of the file)
  1944.  *
  1945.  *   newfile: TRUE when starting to edit a new file, meaning that pe_old_lnum
  1946.  *        will be set for recovery
  1947.  * Check: The caller of this function should probably also call
  1948.  * appended_lines().
  1949.  *
  1950.  * return FAIL for failure, OK otherwise
  1951.  */
  1952.     int
  1953. ml_append(lnum, line, len, newfile)
  1954.     linenr_T    lnum;        /* append after this line (can be 0) */
  1955.     char_u    *line;        /* text of the new line */
  1956.     colnr_T    len;        /* length of new line, including NUL, or 0 */
  1957.     int        newfile;    /* flag, see above */
  1958. {
  1959.     /* When starting up, we might still need to create the memfile */
  1960.     if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL) == FAIL)
  1961.     return FAIL;
  1962.  
  1963.     if (curbuf->b_ml.ml_line_lnum != 0)
  1964.     ml_flush_line(curbuf);
  1965.     return ml_append_int(curbuf, lnum, line, len, newfile, FALSE);
  1966. }
  1967.  
  1968.     static int
  1969. ml_append_int(buf, lnum, line, len, newfile, mark)
  1970.     buf_T    *buf;
  1971.     linenr_T    lnum;        /* append after this line (can be 0) */
  1972.     char_u    *line;        /* text of the new line */
  1973.     colnr_T    len;        /* length of line, including NUL, or 0 */
  1974.     int        newfile;    /* flag, see above */
  1975.     int        mark;        /* mark the new line */
  1976. {
  1977.     int        i;
  1978.     int        line_count;    /* number of indexes in current block */
  1979.     int        offset;
  1980.     int        from, to;
  1981.     int        space_needed;    /* space needed for new line */
  1982.     int        page_size;
  1983.     int        page_count;
  1984.     int        db_idx;        /* index for lnum in data block */
  1985.     bhdr_T    *hp;
  1986.     memfile_T    *mfp;
  1987.     DATA_BL    *dp;
  1988.     PTR_BL    *pp;
  1989.     infoptr_T    *ip;
  1990.  
  1991.                     /* lnum out of range */
  1992.     if (lnum > buf->b_ml.ml_line_count || buf->b_ml.ml_mfp == NULL)
  1993.     return FAIL;
  1994.  
  1995.     if (lowest_marked && lowest_marked > lnum)
  1996.     lowest_marked = lnum + 1;
  1997.  
  1998.     if (len == 0)
  1999.     len = (colnr_T)STRLEN(line) + 1;    /* space needed for the text */
  2000.     space_needed = len + INDEX_SIZE;    /* space needed for text + index */
  2001.  
  2002.     mfp = buf->b_ml.ml_mfp;
  2003.     page_size = mfp->mf_page_size;
  2004.  
  2005. /*
  2006.  * find the data block containing the previous line
  2007.  * This also fills the stack with the blocks from the root to the data block
  2008.  * This also releases any locked block.
  2009.  */
  2010.     if ((hp = ml_find_line(buf, lnum == 0 ? (linenr_T)1 : lnum,
  2011.                               ML_INSERT)) == NULL)
  2012.     return FAIL;
  2013.  
  2014.     buf->b_ml.ml_flags &= ~ML_EMPTY;
  2015.  
  2016.     if (lnum == 0)        /* got line one instead, correct db_idx */
  2017.     db_idx = -1;        /* careful, it is negative! */
  2018.     else
  2019.     db_idx = lnum - buf->b_ml.ml_locked_low;
  2020.         /* get line count before the insertion */
  2021.     line_count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low;
  2022.  
  2023.     dp = (DATA_BL *)(hp->bh_data);
  2024.  
  2025. /*
  2026.  * If
  2027.  * - there is not enough room in the current block
  2028.  * - appending to the last line in the block
  2029.  * - not appending to the last line in the file
  2030.  * insert in front of the next block.
  2031.  */
  2032.     if ((int)dp->db_free < space_needed && db_idx == line_count - 1
  2033.                         && lnum < buf->b_ml.ml_line_count)
  2034.     {
  2035.     /*
  2036.      * Now that the line is not going to be inserted in the block that we
  2037.      * expected, the line count has to be adjusted in the pointer blocks
  2038.      * by using ml_locked_lineadd.
  2039.      */
  2040.     --(buf->b_ml.ml_locked_lineadd);
  2041.     --(buf->b_ml.ml_locked_high);
  2042.     if ((hp = ml_find_line(buf, lnum + 1, ML_INSERT)) == NULL)
  2043.         return FAIL;
  2044.  
  2045.     db_idx = -1;            /* careful, it is negative! */
  2046.             /* get line count before the insertion */
  2047.     line_count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low;
  2048.     CHECK(buf->b_ml.ml_locked_low != lnum + 1, "locked_low != lnum + 1");
  2049.  
  2050.     dp = (DATA_BL *)(hp->bh_data);
  2051.     }
  2052.  
  2053.     ++buf->b_ml.ml_line_count;
  2054.  
  2055.     if ((int)dp->db_free >= space_needed)    /* enough room in data block */
  2056.     {
  2057. /*
  2058.  * Insert new line in existing data block, or in data block allocated above.
  2059.  */
  2060.     dp->db_txt_start -= len;
  2061.     dp->db_free -= space_needed;
  2062.     ++(dp->db_line_count);
  2063.  
  2064.     /*
  2065.      * move the text of the lines that follow to the front
  2066.      * adjust the indexes of the lines that follow
  2067.      */
  2068.     if (line_count > db_idx + 1)        /* if there are following lines */
  2069.     {
  2070.         /*
  2071.          * Offset is the start of the previous line.
  2072.          * This will become the character just after the new line.
  2073.          */
  2074.         if (db_idx < 0)
  2075.         offset = dp->db_txt_end;
  2076.         else
  2077.         offset = ((dp->db_index[db_idx]) & DB_INDEX_MASK);
  2078.         mch_memmove((char *)dp + dp->db_txt_start,
  2079.                       (char *)dp + dp->db_txt_start + len,
  2080.                  (size_t)(offset - (dp->db_txt_start + len)));
  2081.         for (i = line_count - 1; i > db_idx; --i)
  2082.         dp->db_index[i + 1] = dp->db_index[i] - len;
  2083.         dp->db_index[db_idx + 1] = offset - len;
  2084.     }
  2085.     else                    /* add line at the end */
  2086.         dp->db_index[db_idx + 1] = dp->db_txt_start;
  2087.  
  2088.     /*
  2089.      * copy the text into the block
  2090.      */
  2091.     mch_memmove((char *)dp + dp->db_index[db_idx + 1], line, (size_t)len);
  2092.     if (mark)
  2093.         dp->db_index[db_idx + 1] |= DB_MARKED;
  2094.  
  2095.     /*
  2096.      * Mark the block dirty.
  2097.      */
  2098.     buf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
  2099.     if (!newfile)
  2100.         buf->b_ml.ml_flags |= ML_LOCKED_POS;
  2101.     }
  2102.     else        /* not enough space in data block */
  2103.     {
  2104. /*
  2105.  * If there is not enough room we have to create a new data block and copy some
  2106.  * lines into it.
  2107.  * Then we have to insert an entry in the pointer block.
  2108.  * If this pointer block also is full, we go up another block, and so on, up
  2109.  * to the root if necessary.
  2110.  * The line counts in the pointer blocks have already been adjusted by
  2111.  * ml_find_line().
  2112.  */
  2113.     long        line_count_left, line_count_right;
  2114.     int        page_count_left, page_count_right;
  2115.     bhdr_T        *hp_left;
  2116.     bhdr_T        *hp_right;
  2117.     bhdr_T        *hp_new;
  2118.     int        lines_moved;
  2119.     int        data_moved = 0;        /* init to shut up gcc */
  2120.     int        total_moved = 0;        /* init to shut up gcc */
  2121.     DATA_BL        *dp_right, *dp_left;
  2122.     int        stack_idx;
  2123.     int        in_left;
  2124.     int        lineadd;
  2125.     blocknr_T   bnum_left, bnum_right;
  2126.     linenr_T    lnum_left, lnum_right;
  2127.     int        pb_idx;
  2128.     PTR_BL        *pp_new;
  2129.  
  2130.     /*
  2131.      * We are going to allocate a new data block. Depending on the
  2132.      * situation it will be put to the left or right of the existing
  2133.      * block.  If possible we put the new line in the left block and move
  2134.      * the lines after it to the right block. Otherwise the new line is
  2135.      * also put in the right block. This method is more efficient when
  2136.      * inserting a lot of lines at one place.
  2137.      */
  2138.     if (db_idx < 0)        /* left block is new, right block is existing */
  2139.     {
  2140.         lines_moved = 0;
  2141.         in_left = TRUE;
  2142.         /* space_needed does not change */
  2143.     }
  2144.     else            /* left block is existing, right block is new */
  2145.     {
  2146.         lines_moved = line_count - db_idx - 1;
  2147.         if (lines_moved == 0)
  2148.         in_left = FALSE;    /* put new line in right block */
  2149.                     /* space_needed does not change */
  2150.         else
  2151.         {
  2152.         data_moved = ((dp->db_index[db_idx]) & DB_INDEX_MASK) -
  2153.                                 dp->db_txt_start;
  2154.         total_moved = data_moved + lines_moved * INDEX_SIZE;
  2155.         if ((int)dp->db_free + total_moved >= space_needed)
  2156.         {
  2157.             in_left = TRUE;    /* put new line in left block */
  2158.             space_needed = total_moved;
  2159.         }
  2160.         else
  2161.         {
  2162.             in_left = FALSE;        /* put new line in right block */
  2163.             space_needed += total_moved;
  2164.         }
  2165.         }
  2166.     }
  2167.  
  2168.     page_count = ((space_needed + HEADER_SIZE) + page_size - 1) / page_size;
  2169.     if ((hp_new = ml_new_data(mfp, newfile, page_count)) == NULL)
  2170.     {
  2171.             /* correct line counts in pointer blocks */
  2172.         --(buf->b_ml.ml_locked_lineadd);
  2173.         --(buf->b_ml.ml_locked_high);
  2174.         return FAIL;
  2175.     }
  2176.     if (db_idx < 0)        /* left block is new */
  2177.     {
  2178.         hp_left = hp_new;
  2179.         hp_right = hp;
  2180.         line_count_left = 0;
  2181.         line_count_right = line_count;
  2182.     }
  2183.     else            /* right block is new */
  2184.     {
  2185.         hp_left = hp;
  2186.         hp_right = hp_new;
  2187.         line_count_left = line_count;
  2188.         line_count_right = 0;
  2189.     }
  2190.     dp_right = (DATA_BL *)(hp_right->bh_data);
  2191.     dp_left = (DATA_BL *)(hp_left->bh_data);
  2192.     bnum_left = hp_left->bh_bnum;
  2193.     bnum_right = hp_right->bh_bnum;
  2194.     page_count_left = hp_left->bh_page_count;
  2195.     page_count_right = hp_right->bh_page_count;
  2196.  
  2197.     /*
  2198.      * May move the new line into the right/new block.
  2199.      */
  2200.     if (!in_left)
  2201.     {
  2202.         dp_right->db_txt_start -= len;
  2203.         dp_right->db_free -= len + INDEX_SIZE;
  2204.         dp_right->db_index[0] = dp_right->db_txt_start;
  2205.         if (mark)
  2206.         dp_right->db_index[0] |= DB_MARKED;
  2207.  
  2208.         mch_memmove((char *)dp_right + dp_right->db_txt_start,
  2209.                                line, (size_t)len);
  2210.         ++line_count_right;
  2211.     }
  2212.     /*
  2213.      * may move lines from the left/old block to the right/new one.
  2214.      */
  2215.     if (lines_moved)
  2216.     {
  2217.         /*
  2218.          */
  2219.         dp_right->db_txt_start -= data_moved;
  2220.         dp_right->db_free -= total_moved;
  2221.         mch_memmove((char *)dp_right + dp_right->db_txt_start,
  2222.             (char *)dp_left + dp_left->db_txt_start,
  2223.             (size_t)data_moved);
  2224.         offset = dp_right->db_txt_start - dp_left->db_txt_start;
  2225.         dp_left->db_txt_start += data_moved;
  2226.         dp_left->db_free += total_moved;
  2227.  
  2228.         /*
  2229.          * update indexes in the new block
  2230.          */
  2231.         for (to = line_count_right, from = db_idx + 1;
  2232.                      from < line_count_left; ++from, ++to)
  2233.         dp_right->db_index[to] = dp->db_index[from] + offset;
  2234.         line_count_right += lines_moved;
  2235.         line_count_left -= lines_moved;
  2236.     }
  2237.  
  2238.     /*
  2239.      * May move the new line into the left (old or new) block.
  2240.      */
  2241.     if (in_left)
  2242.     {
  2243.         dp_left->db_txt_start -= len;
  2244.         dp_left->db_free -= len + INDEX_SIZE;
  2245.         dp_left->db_index[line_count_left] = dp_left->db_txt_start;
  2246.         if (mark)
  2247.         dp_left->db_index[line_count_left] |= DB_MARKED;
  2248.         mch_memmove((char *)dp_left + dp_left->db_txt_start,
  2249.                                line, (size_t)len);
  2250.         ++line_count_left;
  2251.     }
  2252.  
  2253.     if (db_idx < 0)        /* left block is new */
  2254.     {
  2255.         lnum_left = lnum + 1;
  2256.         lnum_right = 0;
  2257.     }
  2258.     else            /* right block is new */
  2259.     {
  2260.         lnum_left = 0;
  2261.         if (in_left)
  2262.         lnum_right = lnum + 2;
  2263.         else
  2264.         lnum_right = lnum + 1;
  2265.     }
  2266.     dp_left->db_line_count = line_count_left;
  2267.     dp_right->db_line_count = line_count_right;
  2268.  
  2269.     /*
  2270.      * release the two data blocks
  2271.      * The new one (hp_new) already has a correct blocknumber.
  2272.      * The old one (hp, in ml_locked) gets a positive blocknumber if
  2273.      * we changed it and we are not editing a new file.
  2274.      */
  2275.     if (lines_moved || in_left)
  2276.         buf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
  2277.     if (!newfile && db_idx >= 0 && in_left)
  2278.         buf->b_ml.ml_flags |= ML_LOCKED_POS;
  2279.     mf_put(mfp, hp_new, TRUE, FALSE);
  2280.  
  2281.     /*
  2282.      * flush the old data block
  2283.      * set ml_locked_lineadd to 0, because the updating of the
  2284.      * pointer blocks is done below
  2285.      */
  2286.     lineadd = buf->b_ml.ml_locked_lineadd;
  2287.     buf->b_ml.ml_locked_lineadd = 0;
  2288.     ml_find_line(buf, (linenr_T)0, ML_FLUSH);   /* flush data block */
  2289.  
  2290.     /*
  2291.      * update pointer blocks for the new data block
  2292.      */
  2293.     for (stack_idx = buf->b_ml.ml_stack_top - 1; stack_idx >= 0;
  2294.                                   --stack_idx)
  2295.     {
  2296.         ip = &(buf->b_ml.ml_stack[stack_idx]);
  2297.         pb_idx = ip->ip_index;
  2298.         if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
  2299.         return FAIL;
  2300.         pp = (PTR_BL *)(hp->bh_data);   /* must be pointer block */
  2301.         if (pp->pb_id != PTR_ID)
  2302.         {
  2303.         EMSG(_("E317: pointer block id wrong 3"));
  2304.         mf_put(mfp, hp, FALSE, FALSE);
  2305.         return FAIL;
  2306.         }
  2307.         /*
  2308.          * TODO: If the pointer block is full and we are adding at the end
  2309.          * try to insert in front of the next block
  2310.          */
  2311.         /* block not full, add one entry */
  2312.         if (pp->pb_count < pp->pb_count_max)
  2313.         {
  2314.         if (pb_idx + 1 < (int)pp->pb_count)
  2315.             mch_memmove(&pp->pb_pointer[pb_idx + 2],
  2316.                 &pp->pb_pointer[pb_idx + 1],
  2317.             (size_t)(pp->pb_count - pb_idx - 1) * sizeof(PTR_EN));
  2318.         ++pp->pb_count;
  2319.         pp->pb_pointer[pb_idx].pe_line_count = line_count_left;
  2320.         pp->pb_pointer[pb_idx].pe_bnum = bnum_left;
  2321.         pp->pb_pointer[pb_idx].pe_page_count = page_count_left;
  2322.         pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right;
  2323.         pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right;
  2324.         pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right;
  2325.  
  2326.         if (lnum_left != 0)
  2327.             pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left;
  2328.         if (lnum_right != 0)
  2329.             pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right;
  2330.  
  2331.         mf_put(mfp, hp, TRUE, FALSE);
  2332.         buf->b_ml.ml_stack_top = stack_idx + 1;        /* truncate stack */
  2333.  
  2334.         if (lineadd)
  2335.         {
  2336.             --(buf->b_ml.ml_stack_top);
  2337.             /* fix line count for rest of blocks in the stack */
  2338.             ml_lineadd(buf, lineadd);
  2339.                             /* fix stack itself */
  2340.             buf->b_ml.ml_stack[buf->b_ml.ml_stack_top].ip_high +=
  2341.                                       lineadd;
  2342.             ++(buf->b_ml.ml_stack_top);
  2343.         }
  2344.  
  2345.         /*
  2346.          * We are finished, break the loop here.
  2347.          */
  2348.         break;
  2349.         }
  2350.         else            /* pointer block full */
  2351.         {
  2352.         /*
  2353.          * split the pointer block
  2354.          * allocate a new pointer block
  2355.          * move some of the pointer into the new block
  2356.          * prepare for updating the parent block
  2357.          */
  2358.         for (;;)    /* do this twice when splitting block 1 */
  2359.         {
  2360.             hp_new = ml_new_ptr(mfp);
  2361.             if (hp_new == NULL)        /* TODO: try to fix tree */
  2362.             return FAIL;
  2363.             pp_new = (PTR_BL *)(hp_new->bh_data);
  2364.  
  2365.             if (hp->bh_bnum != 1)
  2366.             break;
  2367.  
  2368.             /*
  2369.              * if block 1 becomes full the tree is given an extra level
  2370.              * The pointers from block 1 are moved into the new block.
  2371.              * block 1 is updated to point to the new block
  2372.              * then continue to split the new block
  2373.              */
  2374.             mch_memmove(pp_new, pp, (size_t)page_size);
  2375.             pp->pb_count = 1;
  2376.             pp->pb_pointer[0].pe_bnum = hp_new->bh_bnum;
  2377.             pp->pb_pointer[0].pe_line_count = buf->b_ml.ml_line_count;
  2378.             pp->pb_pointer[0].pe_old_lnum = 1;
  2379.             pp->pb_pointer[0].pe_page_count = 1;
  2380.             mf_put(mfp, hp, TRUE, FALSE);   /* release block 1 */
  2381.             hp = hp_new;        /* new block is to be split */
  2382.             pp = pp_new;
  2383.             CHECK(stack_idx != 0, _("stack_idx should be 0"));
  2384.             ip->ip_index = 0;
  2385.             ++stack_idx;    /* do block 1 again later */
  2386.         }
  2387.         /*
  2388.          * move the pointers after the current one to the new block
  2389.          * If there are none, the new entry will be in the new block.
  2390.          */
  2391.         total_moved = pp->pb_count - pb_idx - 1;
  2392.         if (total_moved)
  2393.         {
  2394.             mch_memmove(&pp_new->pb_pointer[0],
  2395.                 &pp->pb_pointer[pb_idx + 1],
  2396.                 (size_t)(total_moved) * sizeof(PTR_EN));
  2397.             pp_new->pb_count = total_moved;
  2398.             pp->pb_count -= total_moved - 1;
  2399.             pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right;
  2400.             pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right;
  2401.             pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right;
  2402.             if (lnum_right)
  2403.             pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right;
  2404.         }
  2405.         else
  2406.         {
  2407.             pp_new->pb_count = 1;
  2408.             pp_new->pb_pointer[0].pe_bnum = bnum_right;
  2409.             pp_new->pb_pointer[0].pe_line_count = line_count_right;
  2410.             pp_new->pb_pointer[0].pe_page_count = page_count_right;
  2411.             pp_new->pb_pointer[0].pe_old_lnum = lnum_right;
  2412.         }
  2413.         pp->pb_pointer[pb_idx].pe_bnum = bnum_left;
  2414.         pp->pb_pointer[pb_idx].pe_line_count = line_count_left;
  2415.         pp->pb_pointer[pb_idx].pe_page_count = page_count_left;
  2416.         if (lnum_left)
  2417.             pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left;
  2418.         lnum_left = 0;
  2419.         lnum_right = 0;
  2420.  
  2421.         /*
  2422.          * recompute line counts
  2423.          */
  2424.         line_count_right = 0;
  2425.         for (i = 0; i < (int)pp_new->pb_count; ++i)
  2426.             line_count_right += pp_new->pb_pointer[i].pe_line_count;
  2427.         line_count_left = 0;
  2428.         for (i = 0; i < (int)pp->pb_count; ++i)
  2429.             line_count_left += pp->pb_pointer[i].pe_line_count;
  2430.  
  2431.         bnum_left = hp->bh_bnum;
  2432.         bnum_right = hp_new->bh_bnum;
  2433.         page_count_left = 1;
  2434.         page_count_right = 1;
  2435.         mf_put(mfp, hp, TRUE, FALSE);
  2436.         mf_put(mfp, hp_new, TRUE, FALSE);
  2437.         }
  2438.     }
  2439.  
  2440.     /*
  2441.      * Safety check: fallen out of for loop?
  2442.      */
  2443.     if (stack_idx < 0)
  2444.     {
  2445.         EMSG(_("E318: Updated too many blocks?"));
  2446.         buf->b_ml.ml_stack_top = 0;    /* invalidate stack */
  2447.     }
  2448.     }
  2449.  
  2450. #ifdef FEAT_BYTEOFF
  2451.     /* The line was inserted below 'lnum' */
  2452.     ml_updatechunk(buf, lnum + 1, len, ML_CHNK_ADDLINE);
  2453. #endif
  2454.     return OK;
  2455. }
  2456.  
  2457. /*
  2458.  * replace line lnum, with buffering, in current buffer
  2459.  *
  2460.  * If copy is TRUE, make a copy of the line, otherwise the line has been
  2461.  * copied to allocated memory already.
  2462.  *
  2463.  * Check: The caller of this function should probably also call
  2464.  * changed_lines(), unless update_screen(NOT_VALID) is used.
  2465.  *
  2466.  * return FAIL for failure, OK otherwise
  2467.  */
  2468.     int
  2469. ml_replace(lnum, line, copy)
  2470.     linenr_T    lnum;
  2471.     char_u    *line;
  2472.     int        copy;
  2473. {
  2474.     if (line == NULL)        /* just checking... */
  2475.     return FAIL;
  2476.  
  2477.     /* When starting up, we might still need to create the memfile */
  2478.     if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL) == FAIL)
  2479.     return FAIL;
  2480.  
  2481.     if (curbuf->b_ml.ml_line_lnum != lnum)        /* other line buffered */
  2482.     ml_flush_line(curbuf);                /* flush it */
  2483.     else if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY) /* same line allocated */
  2484.     vim_free(curbuf->b_ml.ml_line_ptr);        /* free it */
  2485.     if (copy && (line = vim_strsave(line)) == NULL) /* allocate memory */
  2486.     return FAIL;
  2487.     curbuf->b_ml.ml_line_ptr = line;
  2488.     curbuf->b_ml.ml_line_lnum = lnum;
  2489.     curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY;
  2490.  
  2491.     return OK;
  2492. }
  2493.  
  2494. /*
  2495.  * delete line 'lnum'
  2496.  *
  2497.  * Check: The caller of this function should probably also call
  2498.  * deleted_lines() after this.
  2499.  *
  2500.  * return FAIL for failure, OK otherwise
  2501.  */
  2502.     int
  2503. ml_delete(lnum, message)
  2504.     linenr_T    lnum;
  2505.     int        message;
  2506. {
  2507.     ml_flush_line(curbuf);
  2508.     return ml_delete_int(curbuf, lnum, message);
  2509. }
  2510.  
  2511.     static int
  2512. ml_delete_int(buf, lnum, message)
  2513.     buf_T    *buf;
  2514.     linenr_T    lnum;
  2515.     int        message;
  2516. {
  2517.     bhdr_T    *hp;
  2518.     memfile_T    *mfp;
  2519.     DATA_BL    *dp;
  2520.     PTR_BL    *pp;
  2521.     infoptr_T    *ip;
  2522.     int        count;        /* number of entries in block */
  2523.     int        idx;
  2524.     int        stack_idx;
  2525.     int        text_start;
  2526.     int        line_start;
  2527.     int        line_size;
  2528.     int        i;
  2529.  
  2530.     if (lnum < 1 || lnum > buf->b_ml.ml_line_count)
  2531.     return FAIL;
  2532.  
  2533.     if (lowest_marked && lowest_marked > lnum)
  2534.     lowest_marked--;
  2535.  
  2536. /*
  2537.  * If the file becomes empty the last line is replaced by an empty line.
  2538.  */
  2539.     if (buf->b_ml.ml_line_count == 1)        /* file becomes empty */
  2540.     {
  2541.     if (message)
  2542.     {
  2543.         set_keep_msg((char_u *)_(no_lines_msg));
  2544.         keep_msg_attr = 0;
  2545.     }
  2546.     /* FEAT_BYTEOFF already handled in there, dont worry 'bout it below */
  2547.     i = ml_replace((linenr_T)1, (char_u *)"", TRUE);
  2548.     buf->b_ml.ml_flags |= ML_EMPTY;
  2549.  
  2550.     return i;
  2551.     }
  2552.  
  2553. /*
  2554.  * find the data block containing the line
  2555.  * This also fills the stack with the blocks from the root to the data block
  2556.  * This also releases any locked block.
  2557.  */
  2558.     mfp = buf->b_ml.ml_mfp;
  2559.     if (mfp == NULL)
  2560.     return FAIL;
  2561.  
  2562.     if ((hp = ml_find_line(buf, lnum, ML_DELETE)) == NULL)
  2563.     return FAIL;
  2564.  
  2565.     dp = (DATA_BL *)(hp->bh_data);
  2566.     /* compute line count before the delete */
  2567.     count = (long)(buf->b_ml.ml_locked_high)
  2568.                     - (long)(buf->b_ml.ml_locked_low) + 2;
  2569.     idx = lnum - buf->b_ml.ml_locked_low;
  2570.  
  2571.     --buf->b_ml.ml_line_count;
  2572.  
  2573.     line_start = ((dp->db_index[idx]) & DB_INDEX_MASK);
  2574.     if (idx == 0)        /* first line in block, text at the end */
  2575.     line_size = dp->db_txt_end - line_start;
  2576.     else
  2577.     line_size = ((dp->db_index[idx - 1]) & DB_INDEX_MASK) - line_start;
  2578.  
  2579. /*
  2580.  * special case: If there is only one line in the data block it becomes empty.
  2581.  * Then we have to remove the entry, pointing to this data block, from the
  2582.  * pointer block. If this pointer block also becomes empty, we go up another
  2583.  * block, and so on, up to the root if necessary.
  2584.  * The line counts in the pointer blocks have already been adjusted by
  2585.  * ml_find_line().
  2586.  */
  2587.     if (count == 1)
  2588.     {
  2589.     mf_free(mfp, hp);    /* free the data block */
  2590.     buf->b_ml.ml_locked = NULL;
  2591.  
  2592.     for (stack_idx = buf->b_ml.ml_stack_top - 1; stack_idx >= 0; --stack_idx)
  2593.     {
  2594.         buf->b_ml.ml_stack_top = 0;        /* stack is invalid when failing */
  2595.         ip = &(buf->b_ml.ml_stack[stack_idx]);
  2596.         idx = ip->ip_index;
  2597.         if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
  2598.         return FAIL;
  2599.         pp = (PTR_BL *)(hp->bh_data);   /* must be pointer block */
  2600.         if (pp->pb_id != PTR_ID)
  2601.         {
  2602.         EMSG(_("E317: pointer block id wrong 4"));
  2603.         mf_put(mfp, hp, FALSE, FALSE);
  2604.         return FAIL;
  2605.         }
  2606.         count = --(pp->pb_count);
  2607.         if (count == 0)        /* the pointer block becomes empty! */
  2608.         mf_free(mfp, hp);
  2609.         else
  2610.         {
  2611.         if (count != idx)    /* move entries after the deleted one */
  2612.             mch_memmove(&pp->pb_pointer[idx], &pp->pb_pointer[idx + 1],
  2613.                       (size_t)(count - idx) * sizeof(PTR_EN));
  2614.         mf_put(mfp, hp, TRUE, FALSE);
  2615.  
  2616.         buf->b_ml.ml_stack_top = stack_idx;    /* truncate stack */
  2617.             /* fix line count for rest of blocks in the stack */
  2618.         if (buf->b_ml.ml_locked_lineadd)
  2619.         {
  2620.             ml_lineadd(buf, buf->b_ml.ml_locked_lineadd);
  2621.             buf->b_ml.ml_stack[buf->b_ml.ml_stack_top].ip_high +=
  2622.                         buf->b_ml.ml_locked_lineadd;
  2623.         }
  2624.         ++(buf->b_ml.ml_stack_top);
  2625.  
  2626.         break;
  2627.         }
  2628.     }
  2629.     CHECK(stack_idx < 0, _("deleted block 1?"));
  2630.     }
  2631.     else
  2632.     {
  2633.     /*
  2634.      * delete the text by moving the next lines forwards
  2635.      */
  2636.     text_start = dp->db_txt_start;
  2637.     mch_memmove((char *)dp + text_start + line_size,
  2638.           (char *)dp + text_start, (size_t)(line_start - text_start));
  2639.  
  2640.     /*
  2641.      * delete the index by moving the next indexes backwards
  2642.      * Adjust the indexes for the text movement.
  2643.      */
  2644.     for (i = idx; i < count - 1; ++i)
  2645.         dp->db_index[i] = dp->db_index[i + 1] + line_size;
  2646.  
  2647.     dp->db_free += line_size + INDEX_SIZE;
  2648.     dp->db_txt_start += line_size;
  2649.     --(dp->db_line_count);
  2650.  
  2651.     /*
  2652.      * mark the block dirty and make sure it is in the file (for recovery)
  2653.      */
  2654.     buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
  2655.     }
  2656.  
  2657. #ifdef FEAT_BYTEOFF
  2658.     ml_updatechunk(buf, lnum, line_size, ML_CHNK_DELLINE);
  2659. #endif
  2660.     return OK;
  2661. }
  2662.  
  2663. /*
  2664.  * set the B_MARKED flag for line 'lnum'
  2665.  */
  2666.     void
  2667. ml_setmarked(lnum)
  2668.     linenr_T lnum;
  2669. {
  2670.     bhdr_T    *hp;
  2671.     DATA_BL *dp;
  2672.                     /* invalid line number */
  2673.     if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count
  2674.                            || curbuf->b_ml.ml_mfp == NULL)
  2675.     return;                /* give error message? */
  2676.  
  2677.     if (lowest_marked == 0 || lowest_marked > lnum)
  2678.     lowest_marked = lnum;
  2679.  
  2680.     /*
  2681.      * find the data block containing the line
  2682.      * This also fills the stack with the blocks from the root to the data block
  2683.      * This also releases any locked block.
  2684.      */
  2685.     if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
  2686.     return;            /* give error message? */
  2687.  
  2688.     dp = (DATA_BL *)(hp->bh_data);
  2689.     dp->db_index[lnum - curbuf->b_ml.ml_locked_low] |= DB_MARKED;
  2690.     curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
  2691. }
  2692.  
  2693. /*
  2694.  * find the first line with its B_MARKED flag set
  2695.  */
  2696.     linenr_T
  2697. ml_firstmarked()
  2698. {
  2699.     bhdr_T    *hp;
  2700.     DATA_BL    *dp;
  2701.     linenr_T    lnum;
  2702.     int        i;
  2703.  
  2704.     if (curbuf->b_ml.ml_mfp == NULL)
  2705.     return (linenr_T) 0;
  2706.  
  2707.     /*
  2708.      * The search starts with lowest_marked line. This is the last line where
  2709.      * a mark was found, adjusted by inserting/deleting lines.
  2710.      */
  2711.     for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count; )
  2712.     {
  2713.     /*
  2714.      * Find the data block containing the line.
  2715.      * This also fills the stack with the blocks from the root to the data
  2716.      * block This also releases any locked block.
  2717.      */
  2718.     if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
  2719.         return (linenr_T)0;            /* give error message? */
  2720.  
  2721.     dp = (DATA_BL *)(hp->bh_data);
  2722.  
  2723.     for (i = lnum - curbuf->b_ml.ml_locked_low;
  2724.                 lnum <= curbuf->b_ml.ml_locked_high; ++i, ++lnum)
  2725.         if ((dp->db_index[i]) & DB_MARKED)
  2726.         {
  2727.         (dp->db_index[i]) &= DB_INDEX_MASK;
  2728.         curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
  2729.         lowest_marked = lnum + 1;
  2730.         return lnum;
  2731.         }
  2732.     }
  2733.  
  2734.     return (linenr_T) 0;
  2735. }
  2736.  
  2737. #if 0  /* not used */
  2738. /*
  2739.  * return TRUE if line 'lnum' has a mark
  2740.  */
  2741.     int
  2742. ml_has_mark(lnum)
  2743.     linenr_T    lnum;
  2744. {
  2745.     bhdr_T    *hp;
  2746.     DATA_BL    *dp;
  2747.  
  2748.     if (curbuf->b_ml.ml_mfp == NULL
  2749.             || (hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
  2750.     return FALSE;
  2751.  
  2752.     dp = (DATA_BL *)(hp->bh_data);
  2753.     return (int)((dp->db_index[lnum - curbuf->b_ml.ml_locked_low]) & DB_MARKED);
  2754. }
  2755. #endif
  2756.  
  2757. /*
  2758.  * clear all DB_MARKED flags
  2759.  */
  2760.     void
  2761. ml_clearmarked()
  2762. {
  2763.     bhdr_T    *hp;
  2764.     DATA_BL    *dp;
  2765.     linenr_T    lnum;
  2766.     int        i;
  2767.  
  2768.     if (curbuf->b_ml.ml_mfp == NULL)        /* nothing to do */
  2769.     return;
  2770.  
  2771.     /*
  2772.      * The search starts with line lowest_marked.
  2773.      */
  2774.     for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count; )
  2775.     {
  2776.     /*
  2777.      * Find the data block containing the line.
  2778.      * This also fills the stack with the blocks from the root to the data
  2779.      * block and releases any locked block.
  2780.      */
  2781.     if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
  2782.         return;        /* give error message? */
  2783.  
  2784.     dp = (DATA_BL *)(hp->bh_data);
  2785.  
  2786.     for (i = lnum - curbuf->b_ml.ml_locked_low;
  2787.                 lnum <= curbuf->b_ml.ml_locked_high; ++i, ++lnum)
  2788.         if ((dp->db_index[i]) & DB_MARKED)
  2789.         {
  2790.         (dp->db_index[i]) &= DB_INDEX_MASK;
  2791.         curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
  2792.         }
  2793.     }
  2794.  
  2795.     lowest_marked = 0;
  2796.     return;
  2797. }
  2798.  
  2799. /*
  2800.  * flush ml_line if necessary
  2801.  */
  2802.     static void
  2803. ml_flush_line(buf)
  2804.     buf_T    *buf;
  2805. {
  2806.     bhdr_T    *hp;
  2807.     DATA_BL    *dp;
  2808.     linenr_T    lnum;
  2809.     char_u    *new_line;
  2810.     char_u    *old_line;
  2811.     colnr_T    new_len;
  2812.     int        old_len;
  2813.     int        extra;
  2814.     int        idx;
  2815.     int        start;
  2816.     int        count;
  2817.     int        i;
  2818.  
  2819.     if (buf->b_ml.ml_line_lnum == 0 || buf->b_ml.ml_mfp == NULL)
  2820.     return;        /* nothing to do */
  2821.  
  2822.     if (buf->b_ml.ml_flags & ML_LINE_DIRTY)
  2823.     {
  2824.     lnum = buf->b_ml.ml_line_lnum;
  2825.     new_line = buf->b_ml.ml_line_ptr;
  2826.  
  2827.     hp = ml_find_line(buf, lnum, ML_FIND);
  2828.     if (hp == NULL)
  2829.         EMSGN(_("E320: Cannot find line %ld"), lnum);
  2830.     else
  2831.     {
  2832.         dp = (DATA_BL *)(hp->bh_data);
  2833.         idx = lnum - buf->b_ml.ml_locked_low;
  2834.         start = ((dp->db_index[idx]) & DB_INDEX_MASK);
  2835.         old_line = (char_u *)dp + start;
  2836.         if (idx == 0)    /* line is last in block */
  2837.         old_len = dp->db_txt_end - start;
  2838.         else        /* text of previous line follows */
  2839.         old_len = (dp->db_index[idx - 1] & DB_INDEX_MASK) - start;
  2840.         new_len = (colnr_T)STRLEN(new_line) + 1;
  2841.         extra = new_len - old_len;        /* negative if lines gets smaller */
  2842.  
  2843.         /*
  2844.          * if new line fits in data block, replace directly
  2845.          */
  2846.         if ((int)dp->db_free >= extra)
  2847.         {
  2848.         /* if the length changes and there are following lines */
  2849.         count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low + 1;
  2850.         if (extra != 0 && idx < count - 1)
  2851.         {
  2852.             /* move text of following lines */
  2853.             mch_memmove((char *)dp + dp->db_txt_start - extra,
  2854.                 (char *)dp + dp->db_txt_start,
  2855.                 (size_t)(start - dp->db_txt_start));
  2856.  
  2857.             /* adjust pointers of this and following lines */
  2858.             for (i = idx + 1; i < count; ++i)
  2859.             dp->db_index[i] -= extra;
  2860.         }
  2861.         dp->db_index[idx] -= extra;
  2862.  
  2863.         /* adjust free space */
  2864.         dp->db_free -= extra;
  2865.         dp->db_txt_start -= extra;
  2866.  
  2867.         /* copy new line into the data block */
  2868.         mch_memmove(old_line - extra, new_line, (size_t)new_len);
  2869.         buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
  2870. #ifdef FEAT_BYTEOFF
  2871.         /* The else case is already covered by the insert and delete */
  2872.         ml_updatechunk(buf, lnum, extra, ML_CHNK_UPDLINE);
  2873. #endif
  2874.         }
  2875.         else
  2876.         {
  2877.         /*
  2878.          * Cannot do it in one data block: Delete and append.
  2879.          * Append first, because ml_delete_int() cannot delete the
  2880.          * last line in a buffer, which causes trouble for a buffer
  2881.          * that has only one line.
  2882.          * Don't forget to copy the mark!
  2883.          */
  2884.         /* How about handling errors??? */
  2885.         (void)ml_append_int(buf, lnum, new_line, new_len, FALSE,
  2886.                          (dp->db_index[idx] & DB_MARKED));
  2887.         (void)ml_delete_int(buf, lnum, FALSE);
  2888.         }
  2889.     }
  2890.     vim_free(new_line);
  2891.     }
  2892.  
  2893.     buf->b_ml.ml_line_lnum = 0;
  2894. }
  2895.  
  2896. /*
  2897.  * create a new, empty, data block
  2898.  */
  2899.     static bhdr_T *
  2900. ml_new_data(mfp, negative, page_count)
  2901.     memfile_T    *mfp;
  2902.     int        negative;
  2903.     int        page_count;
  2904. {
  2905.     bhdr_T    *hp;
  2906.     DATA_BL    *dp;
  2907.  
  2908.     if ((hp = mf_new(mfp, negative, page_count)) == NULL)
  2909.     return NULL;
  2910.  
  2911.     dp = (DATA_BL *)(hp->bh_data);
  2912.     dp->db_id = DATA_ID;
  2913.     dp->db_txt_start = dp->db_txt_end = page_count * mfp->mf_page_size;
  2914.     dp->db_free = dp->db_txt_start - HEADER_SIZE;
  2915.     dp->db_line_count = 0;
  2916.  
  2917.     return hp;
  2918. }
  2919.  
  2920. /*
  2921.  * create a new, empty, pointer block
  2922.  */
  2923.     static bhdr_T *
  2924. ml_new_ptr(mfp)
  2925.     memfile_T    *mfp;
  2926. {
  2927.     bhdr_T    *hp;
  2928.     PTR_BL    *pp;
  2929.  
  2930.     if ((hp = mf_new(mfp, FALSE, 1)) == NULL)
  2931.     return NULL;
  2932.  
  2933.     pp = (PTR_BL *)(hp->bh_data);
  2934.     pp->pb_id = PTR_ID;
  2935.     pp->pb_count = 0;
  2936.     pp->pb_count_max = (short_u)((mfp->mf_page_size - sizeof(PTR_BL)) / sizeof(PTR_EN) + 1);
  2937.  
  2938.     return hp;
  2939. }
  2940.  
  2941. /*
  2942.  * lookup line 'lnum' in a memline
  2943.  *
  2944.  *   action: if ML_DELETE or ML_INSERT the line count is updated while searching
  2945.  *         if ML_FLUSH only flush a locked block
  2946.  *         if ML_FIND just find the line
  2947.  *
  2948.  * If the block was found it is locked and put in ml_locked.
  2949.  * The stack is updated to lead to the locked block. The ip_high field in
  2950.  * the stack is updated to reflect the last line in the block AFTER the
  2951.  * insert or delete, also if the pointer block has not been updated yet. But
  2952.  * if if ml_locked != NULL ml_locked_lineadd must be added to ip_high.
  2953.  *
  2954.  * return: NULL for failure, pointer to block header otherwise
  2955.  */
  2956.     static bhdr_T *
  2957. ml_find_line(buf, lnum, action)
  2958.     buf_T    *buf;
  2959.     linenr_T    lnum;
  2960.     int        action;
  2961. {
  2962.     DATA_BL    *dp;
  2963.     PTR_BL    *pp;
  2964.     infoptr_T    *ip;
  2965.     bhdr_T    *hp;
  2966.     memfile_T    *mfp;
  2967.     linenr_T    t;
  2968.     blocknr_T    bnum, bnum2;
  2969.     int        dirty;
  2970.     linenr_T    low, high;
  2971.     int        top;
  2972.     int        page_count;
  2973.     int        idx;
  2974.  
  2975.     mfp = buf->b_ml.ml_mfp;
  2976.  
  2977.     /*
  2978.      * If there is a locked block check if the wanted line is in it.
  2979.      * If not, flush and release the locked block.
  2980.      * Don't do this for ML_INSERT_SAME, because the stack need to be updated.
  2981.      * Don't do this for ML_FLUSH, because we want to flush the locked block.
  2982.      */
  2983.     if (buf->b_ml.ml_locked)
  2984.     {
  2985.     if (ML_SIMPLE(action) && buf->b_ml.ml_locked_low <= lnum
  2986.                       && buf->b_ml.ml_locked_high >= lnum)
  2987.     {
  2988.         /* remember to update pointer blocks and stack later */
  2989.         if (action == ML_INSERT)
  2990.         {
  2991.         ++(buf->b_ml.ml_locked_lineadd);
  2992.         ++(buf->b_ml.ml_locked_high);
  2993.         }
  2994.         else if (action == ML_DELETE)
  2995.         {
  2996.         --(buf->b_ml.ml_locked_lineadd);
  2997.         --(buf->b_ml.ml_locked_high);
  2998.         }
  2999.         return (buf->b_ml.ml_locked);
  3000.     }
  3001.  
  3002.     mf_put(mfp, buf->b_ml.ml_locked, buf->b_ml.ml_flags & ML_LOCKED_DIRTY,
  3003.                         buf->b_ml.ml_flags & ML_LOCKED_POS);
  3004.     buf->b_ml.ml_locked = NULL;
  3005.  
  3006.         /*
  3007.          * if lines have been added or deleted in the locked block, need to
  3008.          * update the line count in pointer blocks
  3009.          */
  3010.     if (buf->b_ml.ml_locked_lineadd)
  3011.         ml_lineadd(buf, buf->b_ml.ml_locked_lineadd);
  3012.     }
  3013.  
  3014.     if (action == ML_FLUSH)        /* nothing else to do */
  3015.     return NULL;
  3016.  
  3017.     bnum = 1;                /* start at the root of the tree */
  3018.     page_count = 1;
  3019.     low = 1;
  3020.     high = buf->b_ml.ml_line_count;
  3021.  
  3022.     if (action == ML_FIND)    /* first try stack entries */
  3023.     {
  3024.     for (top = buf->b_ml.ml_stack_top - 1; top >= 0; --top)
  3025.     {
  3026.         ip = &(buf->b_ml.ml_stack[top]);
  3027.         if (ip->ip_low <= lnum && ip->ip_high >= lnum)
  3028.         {
  3029.         bnum = ip->ip_bnum;
  3030.         low = ip->ip_low;
  3031.         high = ip->ip_high;
  3032.         buf->b_ml.ml_stack_top = top;    /* truncate stack at prev entry */
  3033.         break;
  3034.         }
  3035.     }
  3036.     if (top < 0)
  3037.         buf->b_ml.ml_stack_top = 0;        /* not found, start at the root */
  3038.     }
  3039.     else    /* ML_DELETE or ML_INSERT */
  3040.     buf->b_ml.ml_stack_top = 0;    /* start at the root */
  3041.  
  3042. /*
  3043.  * search downwards in the tree until a data block is found
  3044.  */
  3045.     for (;;)
  3046.     {
  3047.     if ((hp = mf_get(mfp, bnum, page_count)) == NULL)
  3048.         goto error_noblock;
  3049.  
  3050.     /*
  3051.      * update high for insert/delete
  3052.      */
  3053.     if (action == ML_INSERT)
  3054.         ++high;
  3055.     else if (action == ML_DELETE)
  3056.         --high;
  3057.  
  3058.     dp = (DATA_BL *)(hp->bh_data);
  3059.     if (dp->db_id == DATA_ID)    /* data block */
  3060.     {
  3061.         buf->b_ml.ml_locked = hp;
  3062.         buf->b_ml.ml_locked_low = low;
  3063.         buf->b_ml.ml_locked_high = high;
  3064.         buf->b_ml.ml_locked_lineadd = 0;
  3065.         buf->b_ml.ml_flags &= ~(ML_LOCKED_DIRTY | ML_LOCKED_POS);
  3066.         return hp;
  3067.     }
  3068.  
  3069.     pp = (PTR_BL *)(dp);        /* must be pointer block */
  3070.     if (pp->pb_id != PTR_ID)
  3071.     {
  3072.         EMSG(_("E317: pointer block id wrong"));
  3073.         goto error_block;
  3074.     }
  3075.  
  3076.     if ((top = ml_add_stack(buf)) < 0)    /* add new entry to stack */
  3077.         goto error_block;
  3078.     ip = &(buf->b_ml.ml_stack[top]);
  3079.     ip->ip_bnum = bnum;
  3080.     ip->ip_low = low;
  3081.     ip->ip_high = high;
  3082.     ip->ip_index = -1;        /* index not known yet */
  3083.  
  3084.     dirty = FALSE;
  3085.     for (idx = 0; idx < (int)pp->pb_count; ++idx)
  3086.     {
  3087.         t = pp->pb_pointer[idx].pe_line_count;
  3088.         CHECK(t == 0, _("pe_line_count is zero"));
  3089.         if ((low += t) > lnum)
  3090.         {
  3091.         ip->ip_index = idx;
  3092.         bnum = pp->pb_pointer[idx].pe_bnum;
  3093.         page_count = pp->pb_pointer[idx].pe_page_count;
  3094.         high = low - 1;
  3095.         low -= t;
  3096.  
  3097.         /*
  3098.          * a negative block number may have been changed
  3099.          */
  3100.         if (bnum < 0)
  3101.         {
  3102.             bnum2 = mf_trans_del(mfp, bnum);
  3103.             if (bnum != bnum2)
  3104.             {
  3105.             bnum = bnum2;
  3106.             pp->pb_pointer[idx].pe_bnum = bnum;
  3107.             dirty = TRUE;
  3108.             }
  3109.         }
  3110.  
  3111.         break;
  3112.         }
  3113.     }
  3114.     if (idx >= (int)pp->pb_count)        /* past the end: something wrong! */
  3115.     {
  3116.         if (lnum > buf->b_ml.ml_line_count)
  3117.         EMSGN(_("E322: line number out of range: %ld past the end"),
  3118.                           lnum - buf->b_ml.ml_line_count);
  3119.  
  3120.         else
  3121.         EMSGN(_("E323: line count wrong in block %ld"), bnum);
  3122.         goto error_block;
  3123.     }
  3124.     if (action == ML_DELETE)
  3125.     {
  3126.         pp->pb_pointer[idx].pe_line_count--;
  3127.         dirty = TRUE;
  3128.     }
  3129.     else if (action == ML_INSERT)
  3130.     {
  3131.         pp->pb_pointer[idx].pe_line_count++;
  3132.         dirty = TRUE;
  3133.     }
  3134.     mf_put(mfp, hp, dirty, FALSE);
  3135.     }
  3136.  
  3137. error_block:
  3138.     mf_put(mfp, hp, FALSE, FALSE);
  3139. error_noblock:
  3140. /*
  3141.  * If action is ML_DELETE or ML_INSERT we have to correct the tree for
  3142.  * the incremented/decremented line counts, because there won't be a line
  3143.  * inserted/deleted after all.
  3144.  */
  3145.     if (action == ML_DELETE)
  3146.     ml_lineadd(buf, 1);
  3147.     else if (action == ML_INSERT)
  3148.     ml_lineadd(buf, -1);
  3149.     buf->b_ml.ml_stack_top = 0;
  3150.     return NULL;
  3151. }
  3152.  
  3153. /*
  3154.  * add an entry to the info pointer stack
  3155.  *
  3156.  * return -1 for failure, number of the new entry otherwise
  3157.  */
  3158.     static int
  3159. ml_add_stack(buf)
  3160.     buf_T    *buf;
  3161. {
  3162.     int        top;
  3163.     infoptr_T    *newstack;
  3164.  
  3165.     top = buf->b_ml.ml_stack_top;
  3166.  
  3167.     /* may have to increase the stack size */
  3168.     if (top == buf->b_ml.ml_stack_size)
  3169.     {
  3170.     CHECK(top > 0, _("Stack size increases"));    /* more than 5 levels??? */
  3171.  
  3172.     newstack = (infoptr_T *)alloc((unsigned)sizeof(infoptr_T) *
  3173.                     (buf->b_ml.ml_stack_size + STACK_INCR));
  3174.     if (newstack == NULL)
  3175.         return -1;
  3176.     mch_memmove(newstack, buf->b_ml.ml_stack, (size_t)top * sizeof(infoptr_T));
  3177.     vim_free(buf->b_ml.ml_stack);
  3178.     buf->b_ml.ml_stack = newstack;
  3179.     buf->b_ml.ml_stack_size += STACK_INCR;
  3180.     }
  3181.  
  3182.     buf->b_ml.ml_stack_top++;
  3183.     return top;
  3184. }
  3185.  
  3186. /*
  3187.  * Update the pointer blocks on the stack for inserted/deleted lines.
  3188.  * The stack itself is also updated.
  3189.  *
  3190.  * When a insert/delete line action fails, the line is not inserted/deleted,
  3191.  * but the pointer blocks have already been updated. That is fixed here by
  3192.  * walking through the stack.
  3193.  *
  3194.  * Count is the number of lines added, negative if lines have been deleted.
  3195.  */
  3196.     static void
  3197. ml_lineadd(buf, count)
  3198.     buf_T    *buf;
  3199.     int        count;
  3200. {
  3201.     int        idx;
  3202.     infoptr_T    *ip;
  3203.     PTR_BL    *pp;
  3204.     memfile_T    *mfp = buf->b_ml.ml_mfp;
  3205.     bhdr_T    *hp;
  3206.  
  3207.     for (idx = buf->b_ml.ml_stack_top - 1; idx >= 0; --idx)
  3208.     {
  3209.     ip = &(buf->b_ml.ml_stack[idx]);
  3210.     if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
  3211.         break;
  3212.     pp = (PTR_BL *)(hp->bh_data);    /* must be pointer block */
  3213.     if (pp->pb_id != PTR_ID)
  3214.     {
  3215.         mf_put(mfp, hp, FALSE, FALSE);
  3216.         EMSG(_("E317: pointer block id wrong 2"));
  3217.         break;
  3218.     }
  3219.     pp->pb_pointer[ip->ip_index].pe_line_count += count;
  3220.     ip->ip_high += count;
  3221.     mf_put(mfp, hp, TRUE, FALSE);
  3222.     }
  3223. }
  3224.  
  3225. /*
  3226.  * make swap file name out of the file name and a directory name
  3227.  */
  3228.     static char_u *
  3229. makeswapname(buf, dir_name)
  3230.     buf_T    *buf;
  3231.     char_u    *dir_name;
  3232. {
  3233.     char_u    *r, *s;
  3234.  
  3235. #if defined(UNIX) || defined(WIN3264)  /* Need _very_ long file names */
  3236.     s = dir_name + STRLEN(dir_name);
  3237.     if (vim_ispathsep(s[-1]) && s[-1] == s[-2])
  3238.     {                   /* Ends with '//', Use Full path */
  3239.     r = NULL;
  3240.     if ((s = make_percent_swname(dir_name, buf->b_fname)) != NULL)
  3241.     {
  3242.         r = modname(s, (char_u *)".swp", FALSE);
  3243.         vim_free(s);
  3244.     }
  3245.     return r;
  3246.     }
  3247. #endif
  3248.  
  3249.     r = buf_modname(
  3250. #ifdef SHORT_FNAME
  3251.         TRUE,
  3252. #else
  3253.         (buf->b_p_sn || buf->b_shortname),
  3254. #endif
  3255. #ifdef RISCOS
  3256.         /* Avoid problems if fname has special chars, eg <Wimp$Scrap> */
  3257.         buf->b_ffname,
  3258. #else
  3259.         buf->b_fname,
  3260. #endif
  3261.         (char_u *)
  3262. #if defined(VMS) || defined(RISCOS)
  3263.         "_swp",
  3264. #else
  3265.         ".swp",
  3266. #endif
  3267. #ifdef SHORT_FNAME        /* always 8.3 file name */
  3268.         FALSE
  3269. #else
  3270.         /* Prepend a '.' to the swap file name for the current directory. */
  3271.         dir_name[0] == '.' && dir_name[1] == NUL
  3272. #endif
  3273.            );
  3274.     if (r == NULL)        /* out of memory */
  3275.     return NULL;
  3276.  
  3277.     s = get_file_in_dir(r, dir_name);
  3278.     vim_free(r);
  3279.     return s;
  3280. }
  3281.  
  3282. /*
  3283.  * Get file name to use for swap file or backup file.
  3284.  * Use the name of the edited file "fname" and an entry in the 'dir' or 'bdir'
  3285.  * option "dname".
  3286.  * - If "dname" is ".", return "fname" (swap file in dir of file).
  3287.  * - If "dname" starts with "./", insert "dname" in "fname" (swap file
  3288.  *   relative to dir of file).
  3289.  * - Otherwise, prepend "dname" to the tail of "fname" (swap file in specific
  3290.  *   dir).
  3291.  *
  3292.  * The return value is an allocated string and can be NULL.
  3293.  */
  3294.     char_u *
  3295. get_file_in_dir(fname, dname)
  3296.     char_u  *fname;
  3297.     char_u  *dname;    /* don't use "dirname", it is a global for Alpha */
  3298. {
  3299.     char_u    *t;
  3300.     char_u    *tail;
  3301.     char_u    *retval;
  3302.     int        save_char;
  3303.  
  3304.     tail = gettail(fname);
  3305.  
  3306.     if (dname[0] == '.' && dname[1] == NUL)
  3307.     retval = vim_strsave(fname);
  3308.     else if (dname[0] == '.' && vim_ispathsep(dname[1]))
  3309.     {
  3310.     if (tail == fname)        /* no path before file name */
  3311.         retval = concat_fnames(dname + 2, tail, TRUE);
  3312.     else
  3313.     {
  3314.         save_char = *tail;
  3315.         *tail = NUL;
  3316.         t = concat_fnames(fname, dname + 2, TRUE);
  3317.         *tail = save_char;
  3318.         if (t == NULL)        /* out of memory */
  3319.         retval = NULL;
  3320.         else
  3321.         {
  3322.         retval = concat_fnames(t, tail, TRUE);
  3323.         vim_free(t);
  3324.         }
  3325.     }
  3326.     }
  3327.     else
  3328.     retval = concat_fnames(dname, tail, TRUE);
  3329.  
  3330.     return retval;
  3331. }
  3332.  
  3333. /*
  3334.  * Find out what name to use for the swap file for buffer 'buf'.
  3335.  *
  3336.  * Several names are tried to find one that does not exist
  3337.  *
  3338.  * Note: If BASENAMELEN is not correct, you will get error messages for
  3339.  *     not being able to open the swapfile
  3340.  */
  3341.     static char_u *
  3342. findswapname(buf, dirp, old_fname)
  3343.     buf_T    *buf;
  3344.     char_u    **dirp;        /* pointer to list of directories */
  3345.     char_u    *old_fname;    /* don't give warning for this file name */
  3346. {
  3347.     char_u    *fname;
  3348.     int        n;
  3349.     time_t    x, sx;
  3350.     char_u    *dir_name;
  3351. #ifdef AMIGA
  3352.     BPTR    fh;
  3353. #endif
  3354. #ifndef SHORT_FNAME
  3355.     int        r;
  3356. #endif
  3357.  
  3358. #if !defined(SHORT_FNAME) \
  3359.              && ((!defined(UNIX) && !defined(OS2)) || defined(ARCHIE))
  3360. # define CREATE_DUMMY_FILE
  3361.     FILE    *dummyfd = NULL;
  3362.  
  3363. /*
  3364.  * If we start editing a new file, e.g. "test.doc", which resides on an MSDOS
  3365.  * compatible filesystem, it is possible that the file "test.doc.swp" which we
  3366.  * create will be exactly the same file. To avoid this problem we temporarily
  3367.  * create "test.doc".
  3368.  * Don't do this when the check below for a 8.3 file name is used.
  3369.  */
  3370.     if (!(buf->b_p_sn || buf->b_shortname) && buf->b_fname != NULL
  3371.                          && mch_getperm(buf->b_fname) < 0)
  3372.     dummyfd = mch_fopen((char *)buf->b_fname, "w");
  3373. #endif
  3374.  
  3375. /*
  3376.  * Isolate a directory name from *dirp and put it in dir_name.
  3377.  * First allocate some memory to put the directory name in.
  3378.  */
  3379.     dir_name = alloc((unsigned)STRLEN(*dirp) + 1);
  3380.     if (dir_name != NULL)
  3381.     (void)copy_option_part(dirp, dir_name, 31000, ",");
  3382.  
  3383. /*
  3384.  * we try different names until we find one that does not exist yet
  3385.  */
  3386.     if (dir_name == NULL)        /* out of memory */
  3387.     fname = NULL;
  3388.     else
  3389.     fname = makeswapname(buf, dir_name);
  3390.  
  3391.     for (;;)
  3392.     {
  3393.     if (fname == NULL)    /* must be out of memory */
  3394.         break;
  3395.     if ((n = (int)STRLEN(fname)) == 0)    /* safety check */
  3396.     {
  3397.         vim_free(fname);
  3398.         fname = NULL;
  3399.         break;
  3400.     }
  3401. #if (defined(UNIX) || defined(OS2)) && !defined(ARCHIE) && !defined(SHORT_FNAME)
  3402. /*
  3403.  * Some systems have a MS-DOS compatible filesystem that use 8.3 character
  3404.  * file names. If this is the first try and the swap file name does not fit in
  3405.  * 8.3, detect if this is the case, set shortname and try again.
  3406.  */
  3407.     if (fname[n - 2] == 'w' && fname[n - 1] == 'p'
  3408.                     && !(buf->b_p_sn || buf->b_shortname))
  3409.     {
  3410.         char_u        *tail;
  3411.         char_u        *fname2;
  3412.         struct stat        s1, s2;
  3413.         int            f1, f2;
  3414.         int            created1 = FALSE, created2 = FALSE;
  3415.         int            same = FALSE;
  3416.  
  3417.         /*
  3418.          * Check if swapfile name does not fit in 8.3:
  3419.          * It either contains two dots, is longer than 8 chars, or starts
  3420.          * with a dot.
  3421.          */
  3422.         tail = gettail(buf->b_fname);
  3423.         if (       vim_strchr(tail, '.') != NULL
  3424.             || STRLEN(tail) > (size_t)8
  3425.             || *gettail(fname) == '.')
  3426.         {
  3427.         fname2 = alloc(n + 2);
  3428.         if (fname2 != NULL)
  3429.         {
  3430.             STRCPY(fname2, fname);
  3431.             /* if fname == "xx.xx.swp",        fname2 = "xx.xx.swx"
  3432.              * if fname == ".xx.swp",        fname2 = ".xx.swpx"
  3433.              * if fname == "123456789.swp", fname2 = "12345678x.swp"
  3434.              */
  3435.             if (vim_strchr(tail, '.') != NULL)
  3436.             fname2[n - 1] = 'x';
  3437.             else if (*gettail(fname) == '.')
  3438.             {
  3439.             fname2[n] = 'x';
  3440.             fname2[n + 1] = NUL;
  3441.             }
  3442.             else
  3443.             fname2[n - 5] += 1;
  3444.             /*
  3445.              * may need to create the files to be able to use mch_stat()
  3446.              */
  3447.             f1 = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
  3448.             if (f1 < 0)
  3449.             {
  3450.             f1 = open(
  3451. #ifdef VMS
  3452.                 vms_fixfilename((char *)fname),
  3453. #else
  3454.                 (char *)fname,
  3455. #endif
  3456.                 O_RDWR|O_CREAT|O_EXCL|O_EXTRA
  3457. #if defined(UNIX) || defined(VMS)  /* open in rw------- mode */
  3458.                                   , (mode_t)0600
  3459. #endif
  3460. #if defined(MSDOS) || defined(MSWIN) || defined(OS2)  /* open read/write */
  3461.                             , S_IREAD | S_IWRITE
  3462. #endif
  3463.                                         );
  3464. #if defined(OS2)
  3465.             if (f1 < 0 && errno == ENOENT)
  3466.                 same = TRUE;
  3467. #endif
  3468.             created1 = TRUE;
  3469.             }
  3470.             if (f1 >= 0)
  3471.             {
  3472.             f2 = mch_open((char *)fname2, O_RDONLY | O_EXTRA, 0);
  3473.             if (f2 < 0)
  3474.             {
  3475.                 f2 = open(
  3476. #ifdef VMS
  3477.                     vms_fixfilename((char *)fname2),
  3478. #else
  3479.                     (char *)fname2,
  3480. #endif
  3481.                     O_RDWR|O_CREAT|O_EXCL|O_EXTRA
  3482. #if defined(UNIX) || defined(VMS)  /* open in rw------- mode */
  3483.                                   , (mode_t)0600
  3484. #endif
  3485. #if defined(MSDOS) || defined(MSWIN) || defined(OS2)  /* open read/write */
  3486.                             , S_IREAD | S_IWRITE
  3487. #endif
  3488.                                         );
  3489.                 created2 = TRUE;
  3490.             }
  3491.             if (f2 >= 0)
  3492.             {
  3493.                 /*
  3494.                  * Both files exist now. If mch_stat() returns the
  3495.                  * same device and inode they are the same file.
  3496.                  */
  3497.                 if (mch_fstat(f1, &s1) != -1
  3498.                     && mch_fstat(f2, &s2) != -1
  3499.                     && s1.st_dev == s2.st_dev
  3500.                     && s1.st_ino == s2.st_ino)
  3501.                 same = TRUE;
  3502.                 close(f2);
  3503.                 if (created2)
  3504.                 mch_remove(fname2);
  3505.             }
  3506.             close(f1);
  3507.             if (created1)
  3508.                 mch_remove(fname);
  3509.             }
  3510.             vim_free(fname2);
  3511.             if (same)
  3512.             {
  3513.             buf->b_shortname = TRUE;
  3514.             vim_free(fname);
  3515.             fname = makeswapname(buf, dir_name);
  3516.             continue;    /* try again with b_shortname set */
  3517.             }
  3518.         }
  3519.         }
  3520.     }
  3521. #endif
  3522.     /*
  3523.      * check if the swapfile already exists
  3524.      */
  3525.     if (mch_getperm(fname) < 0)    /* it does not exist */
  3526.     {
  3527. #ifdef HAVE_LSTAT
  3528.         struct stat sb;
  3529.  
  3530.         /*
  3531.          * Extra security check: When a swap file is a symbolic link, this
  3532.          * is most likely a symlink attack.
  3533.          */
  3534.         if (mch_lstat((char *)fname, &sb) < 0)
  3535. #else
  3536. # ifdef AMIGA
  3537.         fh = Open((UBYTE *)fname, (long)MODE_NEWFILE);
  3538.         /*
  3539.          * on the Amiga mch_getperm() will return -1 when the file exists
  3540.          * but is being used by another program. This happens if you edit
  3541.          * a file twice.
  3542.          */
  3543.         if (fh != (BPTR)NULL)    /* can open file, OK */
  3544.         {
  3545.         Close(fh);
  3546.         mch_remove(fname);
  3547.         break;
  3548.         }
  3549.         if (IoErr() != ERROR_OBJECT_IN_USE
  3550.                         && IoErr() != ERROR_OBJECT_EXISTS)
  3551. # endif
  3552. #endif
  3553.         break;
  3554.     }
  3555.  
  3556.     /*
  3557.      * A file name equal to old_fname is OK to use.
  3558.      */
  3559.     if (old_fname != NULL && fnamecmp(fname, old_fname) == 0)
  3560.         break;
  3561.  
  3562.     /*
  3563.      * get here when file already exists
  3564.      */
  3565.     if (fname[n - 2] == 'w' && fname[n - 1] == 'p')    /* first try */
  3566.     {
  3567. #ifndef SHORT_FNAME
  3568.         /*
  3569.          * on MS-DOS compatible filesystems (e.g. messydos) file.doc.swp
  3570.          * and file.doc are the same file. To guess if this problem is
  3571.          * present try if file.doc.swx exists. If it does, we set
  3572.          * buf->b_shortname and try file_doc.swp (dots replaced by
  3573.          * underscores for this file), and try again. If it doesn't we
  3574.          * assume that "file.doc.swp" already exists.
  3575.          */
  3576.         if (!(buf->b_p_sn || buf->b_shortname))    /* not tried yet */
  3577.         {
  3578.         fname[n - 1] = 'x';
  3579.         r = mch_getperm(fname);        /* try "file.swx" */
  3580.         fname[n - 1] = 'p';
  3581.         if (r >= 0)            /* "file.swx" seems to exist */
  3582.         {
  3583.             buf->b_shortname = TRUE;
  3584.             vim_free(fname);
  3585.             fname = makeswapname(buf, dir_name);
  3586.             continue;        /* try again with '.' replaced with '_' */
  3587.         }
  3588.         }
  3589. #endif
  3590.         /*
  3591.          * If we get here the ".swp" file really exists.
  3592.          * Give an error message, unless recovering, no file name, we are
  3593.          * viewing a help file or when the path of the file is different
  3594.          * (happens when all .swp files are in one directory).
  3595.          */
  3596.         if (!recoverymode && buf->b_fname != NULL && !buf->b_help)
  3597.         {
  3598.         int        fd;
  3599.         struct block0    b0;
  3600.         int        differ = FALSE;
  3601.  
  3602.         /*
  3603.          * Try to read block 0 from the swap file to get the original
  3604.          * file name (and inode number).
  3605.          */
  3606.         fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
  3607.         if (fd >= 0)
  3608.         {
  3609.             if (read(fd, (char *)&b0, sizeof(b0)) == sizeof(b0))
  3610.             {
  3611.             /*
  3612.              * The name in the swap file may be "~user/path/file".
  3613.              * Expand it first.
  3614.              */
  3615.             expand_env(b0.b0_fname, NameBuff, MAXPATHL);
  3616. #ifdef CHECK_INODE
  3617.             if (fnamecmp_ino(buf->b_ffname, NameBuff,
  3618.                              char_to_long(b0.b0_ino)))
  3619.                 differ = TRUE;
  3620. #else
  3621.             if (fnamecmp(NameBuff, buf->b_ffname) != 0)
  3622.                 differ = TRUE;
  3623. #endif
  3624.             }
  3625.             close(fd);
  3626.         }
  3627. #ifdef RISCOS
  3628.         else
  3629.             /* Can't open swap file, though it does exist.
  3630.              * Assume that the user is editing two files with
  3631.              * the same name in different directories. No error.
  3632.              */
  3633.             differ = TRUE;
  3634. #endif
  3635.  
  3636.         /* give the ATTENTION message when there is an old swap file
  3637.          * for the current file, and the buffer was not recovered. */
  3638.         if (differ == FALSE && !(curbuf->b_flags & BF_RECOVERED)
  3639.             && vim_strchr(p_shm, SHM_ATTENTION) == NULL)
  3640.         {
  3641.             struct stat st;
  3642. #ifdef CREATE_DUMMY_FILE
  3643.             int        did_use_dummy = FALSE;
  3644.  
  3645.             /* Avoid getting a warning for the file being created
  3646.              * outside of Vim, it was created at the start of this
  3647.              * function.  Delete the file now, because Vim might exit
  3648.              * here if the window is closed. */
  3649.             if (dummyfd != NULL)
  3650.             {
  3651.             fclose(dummyfd);
  3652.             dummyfd = NULL;
  3653.             mch_remove(buf->b_fname);
  3654.             did_use_dummy = TRUE;
  3655.             }
  3656. #endif
  3657. #ifdef FEAT_GUI
  3658.             /* If we are supposed to start the GUI but it wasn't
  3659.              * completely started yet, start it now.  This makes the
  3660.              * messages displayed in the Vim window when loading a
  3661.              * session from the .gvimrc file. */
  3662.             if (gui.starting && !gui.in_use)
  3663.             gui_start();
  3664. #endif
  3665.  
  3666. #if (defined(UNIX) || defined(__EMX__) || defined(VMS)) && (defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG))
  3667.             process_still_running = FALSE;
  3668. #endif
  3669.             ++no_wait_return;
  3670.             (void)EMSG(_("E325: ATTENTION"));
  3671.             MSG_PUTS(_("\nFound a swap file by the name \""));
  3672.             msg_home_replace(fname);
  3673.             MSG_PUTS(_("\"\n"));
  3674.             sx = swapfile_info(fname);
  3675.             MSG_PUTS(_("While opening file \""));
  3676.             msg_outtrans(buf->b_fname);
  3677.             MSG_PUTS(_("\"\n"));
  3678.             if (mch_stat((char *)buf->b_fname, &st) != -1)
  3679.             {
  3680.             MSG_PUTS(_("             dated: "));
  3681.             x = st.st_mtime;    /* Manx C can't do &st.st_mtime */
  3682.             MSG_PUTS(ctime(&x));
  3683.             if (sx != 0 && x > sx)
  3684.                 MSG_PUTS(_("      NEWER than swap file!\n"));
  3685.             }
  3686.             /* Some of these messages are long to allow translation to
  3687.              * other languages. */
  3688.             MSG_PUTS(_("\n(1) Another program may be editing the same file.\n    If this is the case, be careful not to end up with two\n    different instances of the same file when making changes.\n"));
  3689.             MSG_PUTS(_("    Quit, or continue with caution.\n"));
  3690.             MSG_PUTS(_("\n(2) An edit session for this file crashed.\n"));
  3691.             MSG_PUTS(_("    If this is the case, use \":recover\" or \"vim -r "));
  3692.             msg_outtrans(buf->b_fname);
  3693.             MSG_PUTS(_("\"\n    to recover the changes (see \":help recovery\").\n"));
  3694.             MSG_PUTS(_("    If you did this already, delete the swap file \""));
  3695.             msg_outtrans(fname);
  3696.             MSG_PUTS(_("\"\n    to avoid this message.\n"));
  3697.             cmdline_row = msg_row;
  3698.             --no_wait_return;
  3699.  
  3700.             /* We don't want a 'q' typed at the more-prompt interrupt
  3701.              * loading a file. */
  3702.             got_int = FALSE;
  3703.  
  3704. #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
  3705.             if (swap_exists_action)
  3706.             {
  3707.             char_u    *name;
  3708.  
  3709.             name = alloc((unsigned)(STRLEN(fname)
  3710.                 + STRLEN(_("Swap file \""))
  3711.                 + STRLEN(_("\" already exists!")) + 5));
  3712.             if (name != NULL)
  3713.             {
  3714.                 STRCPY(name, _("Swap file \""));
  3715.                 home_replace(NULL, fname, name + STRLEN(name),
  3716.                                   1000, TRUE);
  3717.                 STRCAT(name, _("\" already exists!"));
  3718.             }
  3719.             switch (do_dialog(VIM_WARNING,
  3720.                     (char_u *)_("VIM - ATTENTION"),
  3721.                     name == NULL
  3722.                     ?  (char_u *)_("Swap file already exists!")
  3723.                     : name,
  3724. # if defined(UNIX) || defined(__EMX__) || defined(VMS)
  3725.                     process_still_running
  3726.                     ? (char_u *)_("&Open Read-Only\n&Edit anyway\n&Recover\n&Quit") :
  3727. # endif
  3728.                     (char_u *)_("&Open Read-Only\n&Edit anyway\n&Recover\n&Quit\n&Delete it"), 1, NULL))
  3729.             {
  3730.                 case 1:
  3731.                 buf->b_p_ro = TRUE;
  3732.                 break;
  3733.                 case 2:
  3734.                 break;
  3735.                 case 3:
  3736.                 swap_exists_action = SEA_RECOVER;
  3737.                 break;
  3738.                 case 4:
  3739.                 swap_exists_action = SEA_QUIT;
  3740.                 break;
  3741.                 case 5:
  3742.                 mch_remove(fname);
  3743.                 break;
  3744.             }
  3745.             vim_free(name);
  3746.  
  3747.             /* pretend screen didn't scroll, need redraw anyway */
  3748.             msg_scrolled = 0;
  3749.             redraw_all_later(NOT_VALID);
  3750.  
  3751.             /* If the file was deleted this fname can be used. */
  3752.             if (mch_getperm(fname) < 0)
  3753.                 break;
  3754.             }
  3755.             else
  3756. #endif
  3757.             {
  3758.             MSG_PUTS("\n");
  3759.             need_wait_return = TRUE; /* call wait_return later */
  3760.             }
  3761.  
  3762. #ifdef CREATE_DUMMY_FILE
  3763.             /* Going to try another name, need the dummy file again. */
  3764.             if (did_use_dummy)
  3765.             dummyfd = mch_fopen((char *)buf->b_fname, "w");
  3766. #endif
  3767.         }
  3768.         }
  3769.     }
  3770.  
  3771.     /*
  3772.      * Change the ".swp" extension to find another file that can be used.
  3773.      * First decrement the last char: ".swo", ".swn", etc.
  3774.      * If that still isn't enough decrement the last but one char: ".svz"
  3775.      * Can happen when editing many "No File" buffers.
  3776.      */
  3777.     if (fname[n - 1] == 'a')    /* ".s?a" */
  3778.     {
  3779.         if (fname[n - 2] == 'a')    /* ".saa": tried enough, give up */
  3780.         {
  3781.         EMSG(_("E326: Too many swap files found"));
  3782.         vim_free(fname);
  3783.         fname = NULL;
  3784.         break;
  3785.         }
  3786.         --fname[n - 2];        /* ".svz", ".suz", etc. */
  3787.         fname[n - 1] = 'z' + 1;
  3788.     }
  3789.     --fname[n - 1];            /* ".swo", ".swn", etc. */
  3790.     }
  3791.  
  3792.     vim_free(dir_name);
  3793. #ifdef CREATE_DUMMY_FILE
  3794.     if (dummyfd != NULL)    /* file has been created temporarily */
  3795.     {
  3796.     fclose(dummyfd);
  3797.     mch_remove(buf->b_fname);
  3798.     }
  3799. #endif
  3800.     return fname;
  3801. }
  3802.  
  3803.     static int
  3804. b0_magic_wrong(b0p)
  3805.     ZERO_BL *b0p;
  3806. {
  3807.     return (b0p->b0_magic_long != (long)B0_MAGIC_LONG
  3808.         || b0p->b0_magic_int != (int)B0_MAGIC_INT
  3809.         || b0p->b0_magic_short != (short)B0_MAGIC_SHORT
  3810.         || b0p->b0_magic_char != B0_MAGIC_CHAR);
  3811. }
  3812.  
  3813. #ifdef CHECK_INODE
  3814. /*
  3815.  * Compare current file name with file name from swap file.
  3816.  * Try to use inode numbers when possible.
  3817.  * Return non-zero when files are different.
  3818.  *
  3819.  * When comparing file names a few things have to be taken into consideration:
  3820.  * - When working over a network the full path of a file depends on the host.
  3821.  *   We check the inode number if possible.  It is not 100% reliable though,
  3822.  *   because the device number cannot be used over a network.
  3823.  * - When a file does not exist yet (editing a new file) there is no inode
  3824.  *   number.
  3825.  * - The file name in a swap file may not be valid on the current host.  The
  3826.  *   "~user" form is used whenever possible to avoid this.
  3827.  *
  3828.  * This is getting complicated, let's make a table:
  3829.  *
  3830.  *        ino_c  ino_s  fname_c  fname_s    differ =
  3831.  *
  3832.  * both files exist -> compare inode numbers:
  3833.  *        != 0   != 0    X     X    ino_c != ino_s
  3834.  *
  3835.  * inode number(s) unknown, file names available -> compare file names
  3836.  *        == 0    X    OK     OK    fname_c != fname_s
  3837.  *         X     == 0    OK     OK    fname_c != fname_s
  3838.  *
  3839.  * current file doesn't exist, file for swap file exist, file name(s) not
  3840.  * available -> probably different
  3841.  *        == 0   != 0    FAIL     X    TRUE
  3842.  *        == 0   != 0    X    FAIL    TRUE
  3843.  *
  3844.  * current file exists, inode for swap unknown, file name(s) not
  3845.  * available -> probably different
  3846.  *        != 0   == 0    FAIL     X    TRUE
  3847.  *        != 0   == 0    X    FAIL    TRUE
  3848.  *
  3849.  * current file doesn't exist, inode for swap unknown, one file name not
  3850.  * available -> probably different
  3851.  *        == 0   == 0    FAIL     OK    TRUE
  3852.  *        == 0   == 0    OK    FAIL    TRUE
  3853.  *
  3854.  * current file doesn't exist, inode for swap unknown, both file names not
  3855.  * available -> probably same file
  3856.  *        == 0   == 0    FAIL    FAIL    FALSE
  3857.  *
  3858.  * Note that when the ino_t is 64 bits, only the last 32 will be used.  This
  3859.  * can't be changed without making the block 0 incompatible with 32 bit
  3860.  * versions.
  3861.  */
  3862.  
  3863.     static int
  3864. fnamecmp_ino(fname_c, fname_s, ino_block0)
  3865.     char_u    *fname_c;        /* current file name */
  3866.     char_u    *fname_s;        /* file name from swap file */
  3867.     long    ino_block0;
  3868. {
  3869.     struct stat    st;
  3870.     ino_t    ino_c = 0;        /* ino of current file */
  3871.     ino_t    ino_s;            /* ino of file from swap file */
  3872.     char_u    buf_c[MAXPATHL];    /* full path of fname_c */
  3873.     char_u    buf_s[MAXPATHL];    /* full path of fname_s */
  3874.     int        retval_c;        /* flag: buf_c valid */
  3875.     int        retval_s;        /* flag: buf_s valid */
  3876.  
  3877.     if (mch_stat((char *)fname_c, &st) == 0)
  3878.     ino_c = (ino_t)st.st_ino;
  3879.  
  3880.     /*
  3881.      * First we try to get the inode from the file name, because the inode in
  3882.      * the swap file may be outdated.  If that fails (e.g. this path is not
  3883.      * valid on this machine), use the inode from block 0.
  3884.      */
  3885.     if (mch_stat((char *)fname_s, &st) == 0)
  3886.     ino_s = (ino_t)st.st_ino;
  3887.     else
  3888.     ino_s = (ino_t)ino_block0;
  3889.  
  3890.     if (ino_c && ino_s)
  3891.     return (ino_c != ino_s);
  3892.  
  3893.     /*
  3894.      * One of the inode numbers is unknown, try a forced vim_FullName() and
  3895.      * compare the file names.
  3896.      */
  3897.     retval_c = vim_FullName(fname_c, buf_c, MAXPATHL, TRUE);
  3898.     retval_s = vim_FullName(fname_s, buf_s, MAXPATHL, TRUE);
  3899.     if (retval_c == OK && retval_s == OK)
  3900.     return (STRCMP(buf_c, buf_s) != 0);
  3901.  
  3902.     /*
  3903.      * Can't compare inodes or file names, guess that the files are different,
  3904.      * unless both appear not to exist at all.
  3905.      */
  3906.     if (ino_s == 0 && ino_c == 0 && retval_c == FAIL && retval_s == FAIL)
  3907.     return FALSE;
  3908.     return TRUE;
  3909. }
  3910. #endif /* CHECK_INODE */
  3911.  
  3912. /*
  3913.  * Move a long integer into a four byte character array.
  3914.  * Used for machine independency in block zero.
  3915.  */
  3916.     static void
  3917. long_to_char(n, s)
  3918.     long    n;
  3919.     char_u  *s;
  3920. {
  3921.     s[0] = (char_u)(n & 0xff);
  3922.     n = (unsigned)n >> 8;
  3923.     s[1] = (char_u)(n & 0xff);
  3924.     n = (unsigned)n >> 8;
  3925.     s[2] = (char_u)(n & 0xff);
  3926.     n = (unsigned)n >> 8;
  3927.     s[3] = (char_u)(n & 0xff);
  3928. }
  3929.  
  3930.     static long
  3931. char_to_long(s)
  3932.     char_u  *s;
  3933. {
  3934.     long    retval;
  3935.  
  3936.     retval = s[3];
  3937.     retval <<= 8;
  3938.     retval |= s[2];
  3939.     retval <<= 8;
  3940.     retval |= s[1];
  3941.     retval <<= 8;
  3942.     retval |= s[0];
  3943.  
  3944.     return retval;
  3945. }
  3946.  
  3947.     void
  3948. ml_setdirty(buf, flag)
  3949.     buf_T    *buf;
  3950.     int        flag;
  3951. {
  3952.     bhdr_T    *hp;
  3953.     ZERO_BL    *b0p;
  3954.  
  3955.     if (!buf->b_ml.ml_mfp)
  3956.     return;
  3957.     for (hp = buf->b_ml.ml_mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
  3958.     {
  3959.     if (hp->bh_bnum == 0)
  3960.     {
  3961.         b0p = (ZERO_BL *)(hp->bh_data);
  3962.         b0p->b0_dirty = flag ? 0x55 : 0;
  3963.         hp->bh_flags |= BH_DIRTY;
  3964.         mf_sync(buf->b_ml.ml_mfp, MFS_ZERO);
  3965.         break;
  3966.     }
  3967.     }
  3968. }
  3969.  
  3970. #if defined(FEAT_BYTEOFF) || defined(PROTO)
  3971.  
  3972. #define MLCS_MAXL 800    /* max no of lines in chunk */
  3973. #define MLCS_MINL 400   /* should be half of MLCS_MAXL */
  3974.  
  3975. /*
  3976.  * Keep information for finding byte offset of a line, updtytpe may be one of:
  3977.  * ML_CHNK_ADDLINE: Add len to parent chunk, possibly splitting it
  3978.  *       Careful: ML_CHNK_ADDLINE may cause ml_find_line() to be called.
  3979.  * ML_CHNK_DELLINE: Subtract len from parent chunk, possibly deleting it
  3980.  * ML_CHNK_UPDLINE: Add len to parent chunk, as a signed entity.
  3981.  */
  3982.     static void
  3983. ml_updatechunk(buf, line, len, updtype)
  3984.     buf_T    *buf;
  3985.     linenr_T    line;
  3986.     int        len;
  3987.     int        updtype;
  3988. {
  3989.     static buf_T    *ml_upd_lastbuf = NULL;
  3990.     static linenr_T    ml_upd_lastline;
  3991.     static linenr_T    ml_upd_lastcurline;
  3992.     static int        ml_upd_lastcurix;
  3993.  
  3994.     linenr_T        curline = ml_upd_lastcurline;
  3995.     int            curix = ml_upd_lastcurix;
  3996.     long        size;
  3997.     chunksize_T        *curchnk;
  3998.     int            rest;
  3999.     bhdr_T        *hp;
  4000.     DATA_BL        *dp;
  4001.  
  4002.     if (buf->b_ml.ml_usedchunks == -1 || !len)
  4003.     return;
  4004.     if (buf->b_ml.ml_chunksize == NULL)
  4005.     {
  4006.     buf->b_ml.ml_chunksize = (chunksize_T *)
  4007.                   alloc((unsigned)sizeof(chunksize_T) * 100);
  4008.     if (buf->b_ml.ml_chunksize == NULL)
  4009.     {
  4010.         buf->b_ml.ml_usedchunks = -1;
  4011.         return;
  4012.     }
  4013.     buf->b_ml.ml_numchunks = 100;
  4014.     buf->b_ml.ml_usedchunks = 1;
  4015.     buf->b_ml.ml_chunksize[0].mlcs_numlines = 1;
  4016.     buf->b_ml.ml_chunksize[0].mlcs_totalsize = 1;
  4017.     }
  4018.  
  4019.     if (updtype == ML_CHNK_UPDLINE && buf->b_ml.ml_line_count == 1)
  4020.     {
  4021.     /*
  4022.      * First line in empty buffer from ml_flush_line() -- reset
  4023.      */
  4024.     buf->b_ml.ml_usedchunks = 1;
  4025.     buf->b_ml.ml_chunksize[0].mlcs_numlines = 1;
  4026.     buf->b_ml.ml_chunksize[0].mlcs_totalsize =
  4027.                   (long)STRLEN(buf->b_ml.ml_line_ptr) + 1;
  4028.     return;
  4029.     }
  4030.  
  4031.     /*
  4032.      * Find chunk that our line belongs to, curline will be at start of the
  4033.      * chunk.
  4034.      */
  4035.     if (buf != ml_upd_lastbuf || line != ml_upd_lastline + 1
  4036.         || updtype != ML_CHNK_ADDLINE)
  4037.     {
  4038.     for (curline = 1, curix = 0;
  4039.          curix < buf->b_ml.ml_usedchunks - 1
  4040.          && line >= curline + buf->b_ml.ml_chunksize[curix].mlcs_numlines;
  4041.          curix++)
  4042.     {
  4043.         curline += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
  4044.     }
  4045.     }
  4046.     else if (line >= curline + buf->b_ml.ml_chunksize[curix].mlcs_numlines
  4047.          && curix < buf->b_ml.ml_usedchunks - 1)
  4048.     {
  4049.     /* Adjust cached curix & curline */
  4050.     curline += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
  4051.     curix++;
  4052.     }
  4053.     curchnk = buf->b_ml.ml_chunksize + curix;
  4054.  
  4055.     if (updtype == ML_CHNK_DELLINE)
  4056.     len *= -1;
  4057.     curchnk->mlcs_totalsize += len;
  4058.     if (updtype == ML_CHNK_ADDLINE)
  4059.     {
  4060.     curchnk->mlcs_numlines++;
  4061.  
  4062.     /* May resize here so we don't have to do it in both cases below */
  4063.     if (buf->b_ml.ml_usedchunks + 1 >= buf->b_ml.ml_numchunks)
  4064.     {
  4065.         buf->b_ml.ml_numchunks = buf->b_ml.ml_numchunks * 3 / 2;
  4066.         buf->b_ml.ml_chunksize = (chunksize_T *)
  4067.         vim_realloc(buf->b_ml.ml_chunksize,
  4068.                 sizeof(chunksize_T) * buf->b_ml.ml_numchunks);
  4069.         if (buf->b_ml.ml_chunksize == NULL)
  4070.         {
  4071.         /* Hmmmm, Give up on offset for this buffer */
  4072.         buf->b_ml.ml_usedchunks = -1;
  4073.         return;
  4074.         }
  4075.     }
  4076.  
  4077.     if (buf->b_ml.ml_chunksize[curix].mlcs_numlines >= MLCS_MAXL)
  4078.     {
  4079.         int        count;        /* number of entries in block */
  4080.         int        idx;
  4081.         int        text_end;
  4082.         int        linecnt;
  4083.  
  4084.         mch_memmove(buf->b_ml.ml_chunksize + curix + 1,
  4085.             buf->b_ml.ml_chunksize + curix,
  4086.             (buf->b_ml.ml_usedchunks - curix) *
  4087.             sizeof(chunksize_T));
  4088.         /* Compute length of first half of lines in the splitted chunk */
  4089.         size = 0;
  4090.         linecnt = 0;
  4091.         while (curline < buf->b_ml.ml_line_count
  4092.             && linecnt < MLCS_MINL)
  4093.         {
  4094.         if ((hp = ml_find_line(buf, curline, ML_FIND)) == NULL)
  4095.         {
  4096.             buf->b_ml.ml_usedchunks = -1;
  4097.             return;
  4098.         }
  4099.         dp = (DATA_BL *)(hp->bh_data);
  4100.         count = (long)(buf->b_ml.ml_locked_high) -
  4101.             (long)(buf->b_ml.ml_locked_low) + 1;
  4102.         idx = curline - buf->b_ml.ml_locked_low;
  4103.         curline = buf->b_ml.ml_locked_high + 1;
  4104.         if (idx == 0)/* first line in block, text at the end */
  4105.             text_end = dp->db_txt_end;
  4106.         else
  4107.             text_end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK);
  4108.         /* Compute index of last line to use in this MEMLINE */
  4109.         rest = count - idx;
  4110.         if (linecnt + rest > MLCS_MINL)
  4111.         {
  4112.             idx += MLCS_MINL - linecnt - 1;
  4113.             linecnt = MLCS_MINL;
  4114.         }
  4115.         else
  4116.         {
  4117.             idx = count - 1;
  4118.             linecnt += rest;
  4119.         }
  4120.         size += text_end - ((dp->db_index[idx]) & DB_INDEX_MASK);
  4121.         }
  4122.         buf->b_ml.ml_chunksize[curix].mlcs_numlines = linecnt;
  4123.         buf->b_ml.ml_chunksize[curix + 1].mlcs_numlines -= linecnt;
  4124.         buf->b_ml.ml_chunksize[curix].mlcs_totalsize = size;
  4125.         buf->b_ml.ml_chunksize[curix + 1].mlcs_totalsize -= size;
  4126.         buf->b_ml.ml_usedchunks++;
  4127.         ml_upd_lastbuf = NULL;   /* Force recalc of curix & curline */
  4128.         return;
  4129.     }
  4130.     else if (buf->b_ml.ml_chunksize[curix].mlcs_numlines >= MLCS_MINL
  4131.              && curix == buf->b_ml.ml_usedchunks - 1
  4132.              && buf->b_ml.ml_line_count - line <= 1)
  4133.     {
  4134.         /*
  4135.          * We are in the last chunk and it is cheap to crate a new one
  4136.          * after this. Do it now to avoid the loop above later on
  4137.          */
  4138.         curchnk = buf->b_ml.ml_chunksize + curix + 1;
  4139.         buf->b_ml.ml_usedchunks++;
  4140.         if (line == buf->b_ml.ml_line_count)
  4141.         {
  4142.         curchnk->mlcs_numlines = 0;
  4143.         curchnk->mlcs_totalsize = 0;
  4144.         }
  4145.         else
  4146.         {
  4147.         /*
  4148.          * Line is just prior to last, move count for last
  4149.          * This is the common case  when loading a new file
  4150.          */
  4151.         hp = ml_find_line(buf, buf->b_ml.ml_line_count, ML_FIND);
  4152.         if (hp == NULL)
  4153.         {
  4154.             buf->b_ml.ml_usedchunks = -1;
  4155.             return;
  4156.         }
  4157.         dp = (DATA_BL *)(hp->bh_data);
  4158.         if (dp->db_line_count == 1)
  4159.             rest = dp->db_txt_end - dp->db_txt_start;
  4160.         else
  4161.             rest =
  4162.             ((dp->db_index[dp->db_line_count - 2]) & DB_INDEX_MASK)
  4163.             - dp->db_txt_start;
  4164.         curchnk->mlcs_totalsize = rest;
  4165.         curchnk->mlcs_numlines = 1;
  4166.         curchnk[-1].mlcs_totalsize -= rest;
  4167.         curchnk[-1].mlcs_numlines -= 1;
  4168.         }
  4169.     }
  4170.     }
  4171.     else if (updtype == ML_CHNK_DELLINE)
  4172.     {
  4173.     curchnk->mlcs_numlines--;
  4174.     ml_upd_lastbuf = NULL;   /* Force recalc of curix & curline */
  4175.     if (curix < (buf->b_ml.ml_usedchunks - 1)
  4176.         && (curchnk->mlcs_numlines + curchnk[1].mlcs_numlines)
  4177.            <= MLCS_MINL)
  4178.     {
  4179.         curix++;
  4180.         curchnk = buf->b_ml.ml_chunksize + curix;
  4181.     }
  4182.     else if (curix == 0 && curchnk->mlcs_numlines <= 0)
  4183.     {
  4184.         buf->b_ml.ml_usedchunks--;
  4185.         mch_memmove(buf->b_ml.ml_chunksize, buf->b_ml.ml_chunksize + 1,
  4186.             buf->b_ml.ml_usedchunks * sizeof(chunksize_T));
  4187.         return;
  4188.     }
  4189.     else if (curix == 0 || (curchnk->mlcs_numlines > 10
  4190.             && (curchnk->mlcs_numlines + curchnk[-1].mlcs_numlines)
  4191.                > MLCS_MINL))
  4192.     {
  4193.         return;
  4194.     }
  4195.  
  4196.     /* Collapse chunks */
  4197.     curchnk[-1].mlcs_numlines += curchnk->mlcs_numlines;
  4198.     curchnk[-1].mlcs_totalsize += curchnk->mlcs_totalsize;
  4199.     buf->b_ml.ml_usedchunks--;
  4200.     if (curix < buf->b_ml.ml_usedchunks)
  4201.     {
  4202.         mch_memmove(buf->b_ml.ml_chunksize + curix,
  4203.             buf->b_ml.ml_chunksize + curix + 1,
  4204.             (buf->b_ml.ml_usedchunks - curix) *
  4205.             sizeof(chunksize_T));
  4206.     }
  4207.     return;
  4208.     }
  4209.     ml_upd_lastbuf = buf;
  4210.     ml_upd_lastline = line;
  4211.     ml_upd_lastcurline = curline;
  4212.     ml_upd_lastcurix = curix;
  4213. }
  4214.  
  4215. /*
  4216.  * Find offset for line or line with offset.
  4217.  * Find line with offset if line is 0; return remaining offset in offp
  4218.  * Find offset of line if line > 0
  4219.  * return -1 if information is not available
  4220.  */
  4221.     long
  4222. ml_find_line_or_offset(buf, line, offp)
  4223.     buf_T    *buf;
  4224.     linenr_T    line;
  4225.     long    *offp;
  4226. {
  4227.     linenr_T    curline;
  4228.     int        curix;
  4229.     long    size;
  4230.     bhdr_T    *hp;
  4231.     DATA_BL    *dp;
  4232.     int        count;        /* number of entries in block */
  4233.     int        idx;
  4234.     int        start_idx;
  4235.     int        text_end;
  4236.     long    offset;
  4237.     int        len;
  4238.     int        ffdos = (get_fileformat(buf) == EOL_DOS);
  4239.  
  4240.     if (buf->b_ml.ml_usedchunks == -1
  4241.         || buf->b_ml.ml_chunksize == NULL
  4242.         || line < 0)
  4243.     return -1;
  4244.  
  4245.     if (offp == NULL)
  4246.     offset = 0;
  4247.     else
  4248.     offset = *offp;
  4249.     if (line == 0 && offset <= 0)
  4250.     return 1;   /* Not a "find offset" and offset 0 _must_ be in line 1 */
  4251.     /*
  4252.      * Find the last chunk before the one containing our line. Last chunk is
  4253.      * special because it will never qualify
  4254.      */
  4255.     curline = 1;
  4256.     curix = size = 0;
  4257.     while (curix < buf->b_ml.ml_usedchunks - 1
  4258.         && ((line
  4259.          && line >= curline + buf->b_ml.ml_chunksize[curix].mlcs_numlines)
  4260.         || (offset
  4261.        && offset >= size + buf->b_ml.ml_chunksize[curix].mlcs_totalsize
  4262.               + ffdos * buf->b_ml.ml_chunksize[curix].mlcs_numlines)))
  4263.     {
  4264.     curline += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
  4265.     size += buf->b_ml.ml_chunksize[curix].mlcs_totalsize;
  4266.     if (offset && ffdos)
  4267.         size += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
  4268.     curix++;
  4269.     }
  4270.  
  4271.     while ((line && curline < line) || (offset && size < offset))
  4272.     {
  4273.     if (curline > buf->b_ml.ml_line_count
  4274.         || (hp = ml_find_line(buf, curline, ML_FIND)) == NULL)
  4275.     {
  4276.         return -1;
  4277.     }
  4278.     dp = (DATA_BL *)(hp->bh_data);
  4279.     count = (long)(buf->b_ml.ml_locked_high) -
  4280.         (long)(buf->b_ml.ml_locked_low) + 1;
  4281.     start_idx = idx = curline - buf->b_ml.ml_locked_low;
  4282.     if (idx == 0)/* first line in block, text at the end */
  4283.         text_end = dp->db_txt_end;
  4284.     else
  4285.         text_end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK);
  4286.     /* Compute index of last line to use in this MEMLINE */
  4287.     if (line)
  4288.     {
  4289.         if (curline + (count - idx) >= line)
  4290.         idx += line - curline - 1;
  4291.         else
  4292.         idx = count - 1;
  4293.     }
  4294.     else
  4295.     {
  4296.         while (offset >= size
  4297.                + text_end - (int)((dp->db_index[idx]) & DB_INDEX_MASK)
  4298.                                       + ffdos)
  4299.         {
  4300.         if (ffdos)
  4301.             size++;
  4302.         if (idx == count - 1)
  4303.             break;
  4304.         idx++;
  4305.         }
  4306.     }
  4307.     len = text_end - ((dp->db_index[idx]) & DB_INDEX_MASK);
  4308.     size += len;
  4309.     if (offp != NULL && size >= offset)
  4310.     {
  4311.         if (size + ffdos == offset)
  4312.         *offp = 0;
  4313.         else if (idx == start_idx)
  4314.         *offp = offset - size + len;
  4315.         else
  4316.         *offp = offset - size + len
  4317.              - (text_end - ((dp->db_index[idx - 1]) & DB_INDEX_MASK));
  4318.         return curline + idx - start_idx;
  4319.     }
  4320.     curline = buf->b_ml.ml_locked_high + 1;
  4321.     }
  4322.  
  4323.     if (ffdos)
  4324.     size += line - 1;
  4325.     return size;
  4326. }
  4327.  
  4328. /*
  4329.  * Goto byte in buffer with offset 'cnt'.
  4330.  */
  4331.     void
  4332. goto_byte(cnt)
  4333.     long    cnt;
  4334. {
  4335.     long    boff = cnt;
  4336.     linenr_T    lnum;
  4337.  
  4338.     ml_flush_line(curbuf);    /* cached line may be dirty */
  4339.     setpcmark();
  4340.     if (boff)
  4341.     --boff;
  4342.     lnum = ml_find_line_or_offset(curbuf, (linenr_T)0, &boff);
  4343.     if (lnum < 1)    /* past the end */
  4344.     {
  4345.     curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  4346.     curwin->w_curswant = MAXCOL;
  4347.     coladvance((colnr_T)MAXCOL);
  4348.     }
  4349.     else
  4350.     {
  4351.     curwin->w_cursor.lnum = lnum;
  4352.     curwin->w_cursor.col = (colnr_T)boff;
  4353.     curwin->w_set_curswant = TRUE;
  4354.     }
  4355.     check_cursor();
  4356.  
  4357. # ifdef FEAT_MBYTE
  4358.     /* prevent cursor from moving on the trail byte */
  4359.     if (has_mbyte)
  4360.     mb_adjust_cursor();
  4361. # endif
  4362. }
  4363. #endif
  4364.